代码解说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 ...
随机推荐
- 国庆大礼包:2014年最全的ANDROID GUI模板和线框图免费下载
距离上次分享GUI模板有很长时间了,这段时间里设计趋势不断变化,谷歌推出了最新的Android L以及全新的界面设计,UI设计师又有得忙了,今天收集了一组实用的GUI模板和线框图,包含最新的Andro ...
- Java基础(八):多态
一.多态的理解: 多态是同一个行为具有多个不同表现形式或形态的能力. 多态就是同一个接口,使用不同的实例而执行不同操作,如图所示: 多态性是对象多种表现形式的体现:现实中,比如我们按下 F1 键这个动 ...
- 【HowTo ML】分类问题->神经网络入门
非线性分类器(Non-linear hypotheses) 为什么使用非线性分类器 我们举几个栗子: 假如我们有一个数据空间如左上角坐标系所看到的,那么我们要的模型须要如右边公式所看到的的预測函数. ...
- 【SpringCloud】Netflix源码解析之Ribbon:负载均衡策略的定义和实现
Ribbon负载均衡策略定义 IRule其实就只做了一件事情Server choose(Object key),可以看到这个功能是在LB中定义(要求)的,LB把这个功能委托给IRule来实现.不同的I ...
- word图片自动编号与引用(转)
http://blog.csdn.net/hunauchenym/article/details/5915616 用Word时,可能会遇到文中使用了大量的图片的情况,这时,若采用手动为图片编号的方法, ...
- AsyncTask 和 Thread 区别
一.AsyncTask是封装好的线程池,比起Thread+Handler的方式,AsyncTask在操作UI线程上更方便,因为onPreExecute().onPostExecute()及更新UI方法 ...
- angular cli中的--flat参数
添加--flat 参数,表示不创建单独的目录 例如 ng g c news/news-detail 会将文件创建在app/news/news-detail目录下 ng g c news/news-de ...
- JavsScript 之 求时间差
var dateStart = new Date(); //开始时间var dateEnd = new Date(); //结束时间 var timePeriod = dateEnd.getTime( ...
- Smack 结合 Openfire服务器,建立IM通信,发送聊天消息
在文章开始,请你了解和熟悉openfire方面的相关知识,这样对你理解下面代码以及下面代码的用途有很好的了解.同时,你可能需要安装一个简单的CS聊天工具,来测试你的代码是否成功的在openfire服务 ...
- php之快速入门学习-6(字符串变量)
PHP 字符串变量 字符串变量用于存储并处理文本. PHP 中的字符串变量 字符串变量用于包含有字符的值. 在创建字符串之后,我们就可以对它进行操作了.您可以直接在函数中使用字符串,或者把它存储在变量 ...