代码解说Android Scroller、VelocityTracker
在编写自己定义滑动控件时经常会用到Android触摸机制和Scroller及VelocityTracker。Android
Touch系统简单介绍(二):实例具体解释onInterceptTouchEvent与onTouchEvent的调用过程对Android触摸机制须要用到的函数进行了具体的解释。本文主要介绍两个重要的类:Scroller及VelocityTracker。利用上述知识,最后给出了一个自己定义滑动控件的demo,该demo类似于ImageGallery。
ImageGallery通常是用GridView来实现的,能够左右滑动。本样例实现的控件直接继承一个ViewGroup,对其回调函数如
onTouchEvent、onInterceptTouchEvent、computeScroll等进行重载。弄懂该代码。对Android touch的认识将会更深一层。
VelocityTracker:用于对触摸点的速度跟踪,方便获取触摸点的速度。
使用方法:一般在onTouchEvent事件中被调用。先在down事件中获取一个VecolityTracker对象,然后在move或up事件中获取速度,调用流程可例如以下列所看到的:
VelocityTracker vTracker = null;
@Override
public boolean onTouchEvent(MotionEvent event){
int action = event.getAction();
switch(action){
case MotionEvent.ACTION_DOWN:
if(vTracker == null){
vTracker = VelocityTracker.obtain();
}else{
vTracker.clear();
}
vTracker.addMovement(event);
break;
case MotionEvent.ACTION_MOVE:
vTracker.addMovement(event);
//设置单位,1000 表示每秒多少像素(pix/second),1代表每微秒多少像素(pix/millisecond)。
vTracker.computeCurrentVelocity(1000);
//从左向右划返回正数,从右向左划返回负数
System.out.println("the x velocity is "+vTracker.getXVelocity());
//从上往下划返回正数,从下往上划返回负数
System.out.println("the y velocity is "+vTracker.getYVelocity());
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
vTracker.recycle();
break;
}
return true;
}
Scroller:用于跟踪控件滑动的轨迹。此类不会移动控件,须要你在View的一个回调函数computerScroll()中使用Scroller对象还获取滑动的数据来控制某个View。
/**
* Called by a parent to request that a child update its values for mScrollX
* and mScrollY if necessary. This will typically be done if the child is
* animating a scroll using a {@link android.widget.Scroller Scroller}
* object.
*/
public void computeScroll()
{
}
parentView在绘制式。会调用dispatchDraw(Canvas canvas),该函数会调用ViewGroup中的每一个子view的boolean draw(Canvas canvas, ViewGroup parent, long drawingTime),用户绘制View,此函数在绘制View的过程中会调用computeScroll()
以下给出一段代码:
@Override
public void computeScroll() {
// TODO Auto-generated method stub
Log.e(TAG, "computeScroll");
if (mScroller.computeScrollOffset()) { //or !mScroller.isFinished()
Log.e(TAG, mScroller.getCurrX() + "======" + mScroller.getCurrY());
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
Log.e(TAG, "### getleft is " + getLeft() + " ### getRight is " + getRight());
postInvalidate();
}
else
Log.i(TAG, "have done the scoller -----");
}
这段代码在滑动view之前先调用mScroller.computeScrollOffset()来推断滑动动画是否已结束。computerScrollerOffset()的源码例如以下:
/**
* Call this when you want to know the new location. If it returns true,
* the animation is not yet finished.
*/
public boolean computeScrollOffset() {
if (mFinished) {
return false;
} //滑动已经持续的时间
int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
//若在规定时间还未用完,则继续设置新的滑动位置mCurrX和mCurry
if (timePassed < mDuration) {
switch (mMode) {
case SCROLL_MODE:
float x = timePassed * mDurationReciprocal; if (mInterpolator == null)
x = viscousFluid(x);
else
x = mInterpolator.getInterpolation(x); mCurrX = mStartX + Math.round(x * mDeltaX);
mCurrY = mStartY + Math.round(x * mDeltaY);
break;
case FLING_MODE:
final float t = (float) timePassed / mDuration;
final int index = (int) (NB_SAMPLES * t);
float distanceCoef = 1.f;
float velocityCoef = 0.f;
if (index < NB_SAMPLES) {
final float t_inf = (float) index / NB_SAMPLES;
final float t_sup = (float) (index + 1) / NB_SAMPLES;
final float d_inf = SPLINE_POSITION[index];
final float d_sup = SPLINE_POSITION[index + 1];
velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
distanceCoef = d_inf + (t - t_inf) * velocityCoef;
} mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f; mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
// Pin to mMinX <= mCurrX <= mMaxX
mCurrX = Math.min(mCurrX, mMaxX);
mCurrX = Math.max(mCurrX, mMinX); mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
// Pin to mMinY <= mCurrY <= mMaxY
mCurrY = Math.min(mCurrY, mMaxY);
mCurrY = Math.max(mCurrY, mMinY); if (mCurrX == mFinalX && mCurrY == mFinalY) {
mFinished = true;
} break;
}
}
else {
mCurrX = mFinalX;
mCurrY = mFinalY;
mFinished = true;
}
return true;
}
ViewGroup.computeScroll()被调用时机:
当我们运行ontouch或invalidate()或postInvalidate()都会导致这种方法的运行。
我们在开发控件时。常会有这种需求:当单机某个button时。某个图片会在规定的时间内滑出窗体。而不是一下子进入窗体。实现这个功能能够使用Scroller来实现。
以下给出一段代码,该代码控制下一个界面在3秒时间内缓慢进入的效果。
public void moveToRightSide(){
if (curScreen <= 0) {
return;
}
curScreen-- ;
Log.i(TAG, "----moveToRightSide---- curScreen " + curScreen);
mScroller.startScroll((curScreen + 1) * getWidth(), 0, -getWidth(), 0, 3000);
scrollTo(curScreen * getWidth(), 0);
invalidate();
}
上述代码用到了一个函数:void android.widget.Scroller.startScroll(int startX, int startY, int dx, int dy, int duration)
当startScroll运行过程中即在duration时间内,computeScrollOffset 方法会一直返回true,但当动画运行完毕后会返回返加false.
这个函数的源代码例如以下所看到的,主要用于设置滑动參数
/**
* Start scrolling by providing a starting point, the distance to travel,
* and the duration of the scroll.
*
* @param startX Starting horizontal scroll offset in pixels. Positive
* numbers will scroll the content to the left.
* @param startY Starting vertical scroll offset in pixels. Positive numbers
* will scroll the content up.
* @param dx Horizontal distance to travel. Positive numbers will scroll the
* content to the left.
* @param dy Vertical distance to travel. Positive numbers will scroll the
* content up.
* @param duration Duration of the scroll in milliseconds.
*/
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mMode = SCROLL_MODE;
mFinished = false;
mDuration = duration;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
mFinalX = startX + dx;
mFinalY = startY + dy;
mDeltaX = dx;
mDeltaY = dy;
mDurationReciprocal = 1.0f / (float) mDuration;
}
invalidate()会使得视图重绘,导致parent调用了dispatchDraw(Canvas canvas),然后递归调用child View的draw()函数。该函数又会调用我们定义的computeScroll(), 而这个函数又会调用mScroller.computeScrollOffset()推断动画是否结束。若没结束则继续重绘直到直到startScroll中设置的时间耗尽mScroller.computeScrollOffset()返回false才停下来。
附上完整的实例代码:
自己定义Android可滑动控件源代码
执行效果图例如以下,滑动屏幕会显示不同的图片。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmlnY29udmllbmNl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" style="font-size:10px; font-family:'Microsoft YaHei'; line-height:30px">
代码解说Android Scroller、VelocityTracker的更多相关文章
- 代码讲解Android Scroller、VelocityTracker
在编写自定义滑动控件时常常会用到Android触摸机制和Scroller及VelocityTracker.Android Touch系统简介(二):实例详解onInterceptTouchEvent与 ...
- Android Scroller解析
作用 这个类封装了滚动操作,如帮我们处理手指抬起来时候的滑动操作.与ViewGroup的scrollTo(),scrollBy()的生硬式移动,Scroller提供了一个更加柔和的移动效果.Scrol ...
- 一行代码解决Android M新的运行时权限问题
Android M运行时权限是个啥东西 啥是运行时权限呢?Android M对权限管理系统进行了改版,之前我们的App需要权限,只需在manifest中申明即可,用户安装后,一切申明的权限都可来去自如 ...
- 用kotlin方式打开《第一行代码:Android》
参考:<第一行代码:Android>第2版--郭霖 注1:本文为原创,例子可参考郭前辈著作:<第一行代码:Android> 注2:本文不赘述android开发的基本理论,不介绍 ...
- 用kotlin方式打开《第一行代码:Android》之开发酷欧天气(1)
参考:<第一行代码:Android>第2版--郭霖 注1:本文为原创,例子可参考郭前辈著作:<第一行代码:Android>第2版 注2:本文不赘述android开发的基本理论, ...
- 第四章:重构代码[学习Android Studio汉化教程]
第四章 Refactoring Code The solutions you develop in Android Studio will not always follow a straight p ...
- Android Scroller详解
在学习使用Scroller之前,需要明白scrollTo().scrollBy()方法. 一.View的scrollTo().scrollBy() scrollTo.scrollBy方法是View中的 ...
- android Scroller类的理解
Scroller 一个特例: **点击Button后可能View没有移动,要关闭硬件加速,这段代码中int detalX = (int) (event.getX() - downX)要更正. demo ...
- Android Scroller类的详细分析
尊重原创作者,转载请注明出处: http://blog.csdn.net/gemmem/article/details/7321910 Scroller这个类理解起来有一定的困难,刚开始接触Scrol ...
随机推荐
- C++初始化列表和大括号中构造的差别
C++的对象构造函数有两种初始化的方法: 1.初始化列表 2.大括号中面赋值 这两种推荐使用另外一种.原因在于使用初始化列表仅仅须要进行一次初始化.而使用大括号内赋值的话首先须要调用默认构造函数初始化 ...
- 基于Sql Server 2008的分布式数据库的实践(终结)
学习.操作心得 以前在做网站程序的时候一直用的是MYSQL,但是网上搜到MYSQL不支持分布式操作,然后便开始查询MSSQL的分布式数据库的设计与操作,后来在网上找到了<基于SQL SERVER ...
- 解决spark中遇到的数据倾斜问题
一. 数据倾斜的现象 多数task执行速度较快,少数task执行时间非常长,或者等待很长时间后提示你内存不足,执行失败. 二. 数据倾斜的原因 常见于各种shuffle操作,例如reduceByKey ...
- [置顶] Android异步加载数据库和多线程编程
Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发.尚未有统一中文名称,中国大陆地区较多人使用“安卓” ...
- java 读取本地的json文件
首先,要先去下载相关的jar包,否则你是无法做到的. 在百度或者谷歌里面输入java json jar包下载就行了(共7个包). xom-1.1.jar ezmorph-1.0.6.jar json ...
- Mongo命令批量更新某一数组字段的顺序
db.table.find().forEach(function (doc) { var oldValue = doc.Column1; var newValue = [sa[1] ...
- Android直播实现 Android端推流、播放
最近想实现一个Android直播,但是对于这方面的资料都比较零碎,一开始是打算用ffmpeg来实现编码推流,在搜集资料期间,找到了几个强大的开源库,直接避免了jni的代码,集成后只用少量的java代码 ...
- 《linux 内核全然剖析》 sys.c 代码分析
sys.c 代码分析 setregid /* * This is done BSD-style, with no consideration of the saved gid, except * th ...
- 矩阵经典题目四:送给圣诞夜的礼品(使用m个置换实现对序列的转变)
https://vijos.org/p/1049 给出一个序列,含n个数.然后是m个置换,求对初始序列依次进行k次置换,求最后的序列. 先看一个置换.把置换表示成矩阵的形式.然后将m个置换乘起来.那么 ...
- PS中标尺工具在哪里
打开photoshop应用程序,然后在PS菜单中点击“视图——标尺”选项即可打开ps标尺栏. 单位设置: 按Ctrl+K快捷键会弹出“首选项”对话框,你选择“单位与标尺”项,在“单位”一栏里 ...