Android里Scroller类是为了实现View平滑滚动的一个Helper类。通常在自定义的View时使用,在View中定义一个私有成员mScroller = new Scroller(context)。设置mScroller滚动的位置时,并不会导致View的滚动,通常是用mScroller记录/计算View滚动的位置,再重写View的computeScroll(),完成实际的滚动。 相关API介绍如下


OverScroller

[java] view plain copy
  1. mScroller.getCurrX() //获取mScroller当前水平滚动的位置  
  2. mScroller.getCurrY() //获取mScroller当前竖直滚动的位置  
  3. mScroller.getFinalX() //获取mScroller最终停止的水平位置  
  4. mScroller.getFinalY() //获取mScroller最终停止的竖直位置  
  5. mScroller.setFinalX(int newX) //设置mScroller最终停留的水平位置,没有动画效果,直接跳到目标位置  
  6. mScroller.setFinalY(int newY) //设置mScroller最终停留的竖直位置,没有动画效果,直接跳到目标位置  
  7.   
  8. //滚动,startX, startY为开始滚动的位置,dx,dy为滚动的偏移量, duration为完成滚动的时间  
  9. mScroller.startScroll(int startX, int startY, int dx, int dy) //使用默认完成时间250ms  
  10. mScroller.startScroll(int startX, int startY, int dx, int dy, int duration)  
  11.   
  12. mScroller.computeScrollOffset() //返回值为boolean,true说明滚动尚未完成,false说明滚动已经完成。这是一个很重要的方法,通常放在View.computeScroll()中,用来判断是否滚动是否结束。  

举例说明,自定义一个CustomView,使用Scroller实现滚动:

[java] view plain copy 在CODE上查看代码片派生到我的代码片    import android.content.Context;      import android.util.AttributeSet;      import android.util.Log;      import android.view.View;      import android.widget.LinearLayout;      import android.widget.Scroller;            public class CustomView extends LinearLayout {                private static final String TAG = "Scroller";                private OverScroller mScroller;                public CustomView(Context context, AttributeSet attrs) {              super(context, attrs);              mScroller = new OverScroller(context);          }                //调用此方法滚动到目标位置          public void smoothScrollTo(int fx, int fy) {              int dx = fx - mScroller.getFinalX();              int dy = fy - mScroller.getFinalY();              smoothScrollBy(dx, dy);          }                //调用此方法设置滚动的相对偏移          public void smoothScrollBy(int dx, int dy) {                    //设置mScroller的滚动偏移量              mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);              invalidate();//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果          }                    @Override          public void computeScroll() {                        //先判断mScroller滚动是否完成              if (mScroller.computeScrollOffset()) {                                //这里调用View的scrollTo()完成实际的滚动                  scrollTo(mScroller.getCurrX(), mScroller.getCurrY());                                    //必须调用该方法,否则不一定能看到滚动效果                  postInvalidate();              }              super.computeScroll();          }      }  



VelocityTracker

VelocityTracker是一个什么东西呢,查看VelocityTracker源代码发现有如下注释:

[html] view plain copy print ?
  1. /**  
  2.     * Helper for tracking the velocity of touch events, for implementing  
  3.     * flinging and other such gestures.  
  4.     *  
  5.     * Use {@link #obtain} to retrieve a new instance of the class when you are going  
  6.     * to begin tracking.  Put the motion events you receive into it with  
  7.     * {@link #addMovement(android.view.MotionEvent)}.  When you want to determine the velocity call  
  8.     * {@link #computeCurrentVelocity(int)} and then call {@link #getXVelocity(int)}  
  9.     * and {@link #getYVelocity(int)} to retrieve the velocity for each pointer id.  
  10.     *  
  11.     * 追踪触摸事件速率,实现flinging和其他手势的帮助类  
  12.     *  
  13.     * 1、当开始追踪的时候,使用obtain来获取VelocityTracker类的实例  
  14.     * 2、把接收到的MotionEvent放入到addMovement(android.view.MotionEvent)中  
  15.     * 3、当要确定速度时调用computeCurrentVelocity(int),  
  16.     *   使用getXVelocity(int)和getYVelocity(int)来检测每个触摸点id的速率  
  17.     */  

VelocityTracker是一个帮助追踪触摸事件速率的追踪器,可以追踪fliinging和其他触摸手势。

如何使用VelocityTracker呢,注释中提到如下步骤:

[html] view plain copy print ?
  1. 1、当开始追踪的时候,使用obtain来获取VelocityTracker类的实例  
  2. 2、把接受到的MotionEvent放入到addMovement(android.view.MotionEvent)中  
  3. 3、当要确定速度时调用computeCurrentVelocity(int),  
  4.       使用getXVelocity(int)和getYVelocity(int)来检测每个触摸点id的速率  

既然VelocityTracker是追踪触摸事件的速度追踪器,当然需要与触摸事件结合使用。

第一步:当你想要追踪触摸事件的速度时,使用private VelocityTracker mVelocityTracker = VelocityTracker.obtain();来获取一个实例,

obtain()方法的源代码:

[java] view plain copy print ?
  1. /** 
  2.   * Retrieve a new VelocityTracker object to watch the velocity of a 
  3.   * motion.  Be sure to call {@link #recycle} when done.  You should 
  4.   * generally only maintain an active object while tracking a movement, 
  5.   * so that the VelocityTracker can be re-used elsewhere. 
  6.   * 
  7.   * @return Returns a new VelocityTracker. 
  8.   * 
  9.   * 获取一个新的VelocityTracker对象,用于检测一个动作的速率 
  10.   * 检测结束时确保调用了recycle()方法来回收VelocityTracker对象 
  11.   * 追踪一个移动事件时通常只需要维护一个活动对象,这样VelocityTracker可以被重用 
  12.   */  
  13.  static public VelocityTracker obtain() {  
  14.      VelocityTracker instance = sPool.acquire();  
  15.      return (instance != null) ? instance : new VelocityTracker(null);  
  16.  }  

第二步:把接收到的MotionEvent放入到addMovement(MotionEvent event)方法中,

在初始化MotionEvent的ACTION_DOWN时调用addMovement(MotionEvent event)

然后在ACTION_MOVE和ACTION_UP动作中就可以检测到速度了。

[java] view plain copy print ?
  1. /** 
  2.     * Add a user's movement to the tracker.  You should call this for the 
  3.     * initial {@link MotionEvent#ACTION_DOWN}, the following 
  4.     * {@link MotionEvent#ACTION_MOVE} events that you receive, and the 
  5.     * final {@link MotionEvent#ACTION_UP}.  You can, however, call this 
  6.     * for whichever events you desire. 
  7.     * 
  8.     * @param event The MotionEvent you received and would like to track. 
  9.     * 
  10.     * 添加一个移动事件到追踪器 
  11.     * 1.为初始化MotionEvent的ACTION_DOWN动作调用addMovement() 
  12.     * 2.接下来,在MotionEvent的ACTION_MOVE和ACTION_UP动作中接收。 
  13.     *    不管是哪一个events都可以调用本方法 
  14.     */  
  15.    public void addMovement(MotionEvent event) {  
  16.        if (event == null) {  
  17.            throw new IllegalArgumentException("event must not be null");  
  18.        }  
  19.        nativeAddMovement(mPtr, event);  
  20.    }  

第三步:想要确定速度的时候调用computeCurrentVelocity(int units)方法。有两个同样的方法,一个带有最大值参数,默认为Float.MAX_VALUE [java] view plain copy print ?
  1. /** 
  2.  * Compute the current velocity based on the points that have been 
  3.  * collected.  Only call this when you actually want to retrieve velocity 
  4.  * information, as it is relatively expensive.  You can then retrieve 
  5.  * the velocity with {@link #getXVelocity()} and 
  6.  * {@link #getYVelocity()}. 
  7.  * 根据收集到的触摸点计算当前速率 
  8.  * 因为此方法相当消耗性能,所以只有当真的确实想要检测速度信息的时候才调用这个方法 
  9.  * 然后可以通过getXVelocity()和getYVelocity()方法获取到追踪的速度 
  10.  * 
  11.  * @param units The units you would like the velocity in.  A value of 1 
  12.  * provides pixels per millisecond, 1000 provides pixels per second, etc. 
  13.  *        units :代表速度的单位, 
  14.  *              值为1时:代表每毫秒运动一个像素,px/ms 
  15.  *              值为1000时:代表每秒运动1000个像素,1000px/s 
  16.  * @param maxVelocity The maximum velocity that can be computed by this method. 
  17.  * This value must be declared in the same unit as the units parameter. This value 
  18.  * must be positive. 
  19.  *        maxVelocity :代表可以被本方法计算的最大速度, 
  20.  *                    这个值必须用同一个作为速度参数的单位声明,而且值必须为正数 
  21.  */  
  22. public void computeCurrentVelocity(int units, float maxVelocity) {  
  23.     nativeComputeCurrentVelocity(mPtr, units, maxVelocity);  
  24. }  

[java] view plain copy print ?
  1. /** 
  2.     * Equivalent to invoking {@link #computeCurrentVelocity(int, float)} with a maximum 
  3.     * velocity of Float.MAX_VALUE. 
  4.     * 
  5.     * @see #computeCurrentVelocity(int, float) 
  6.     *  
  7.     * 等价调用带有最大值为Float.MAX_VALUE的computeCurrentVelocity(int, float)方法, 
  8.     */  
  9.    public void computeCurrentVelocity(int units) {  
  10.        nativeComputeCurrentVelocity(mPtr, units, Float.MAX_VALUE);  
  11.    }  

第四步:使用getXVelocity()和getYVelocity()方法获取检测到的速度

获取X轴方向的速度:

[java] view plain copy print ?
  1. /** 
  2.     * Retrieve the last computed X velocity.  You must first call 
  3.     * {@link #computeCurrentVelocity(int)} before calling this function. 
  4.     *  
  5.     * 检测最后计算的X轴方向的速度,在调用getXVelocity()之前必须先调用computeCurrentVelocity(int) 
  6.     * @return The previously computed X velocity. 
  7.     */  
  8.    public float getXVelocity() {  
  9.        return nativeGetXVelocity(mPtr, ACTIVE_POINTER_ID);  
  10.    }  
获取Y轴方向上的速度:
[java] view plain copy print ?
  1. /** 
  2.      * Retrieve the last computed Y velocity.  You must first call 
  3.      * {@link #computeCurrentVelocity(int)} before calling this function. 
  4.      * 
  5.      * 检测最后计算的X轴方向的速度,在调用getXVelocity()之前必须先调用computeCurrentVelocity(int) 
  6.      * @return The previously computed Y velocity. 
  7.      */  
  8.     public float getYVelocity() {  
  9.         return nativeGetYVelocity(mPtr, ACTIVE_POINTER_ID);  
  10.     }  

第五步:回收VelocityTracker实例 [java] view plain copy print ?
  1. /** 
  2.    * Return a VelocityTracker object back to be re-used by others.  You must 
  3.    * not touch the object after calling this function. 
  4.    * 
  5.    * 回收一个VelocityTracker对象给其他动作事件使用 
  6.    * 在调用recycle()这个函数之后,你不能访问VelocityTracker对象 
  7.    */  
  8.   public void recycle() {  
  9.       if (mStrategy == null) {  
  10.           clear();  
  11.           sPool.release(this);  
  12.       }  
  13.   }  


小实例:

[java] view plain copy print ?
  1. package com.zwc.admin.scrollerdemo;  
  2.   
  3. import android.support.v7.app.ActionBarActivity;  
  4. import android.os.Bundle;  
  5. import android.util.Log;  
  6. import android.view.MotionEvent;  
  7. import android.view.VelocityTracker;  
  8.   
  9.   
  10. public class VelocityTrackerTestActivity extends ActionBarActivity {  
  11.   
  12.     private static final String TAG = "VelocityTrackerTestActivity";  
  13.   
  14.     private VelocityTracker mVelocityTracker;  
  15.     private int mPointerId;  
  16.   
  17.     @Override  
  18.     protected void onCreate(Bundle savedInstanceState) {  
  19.         super.onCreate(savedInstanceState);  
  20.         setContentView(R.layout.activity_velocity_tracker_test);  
  21.     }  
  22.   
  23.     @Override  
  24.     public boolean onTouchEvent(MotionEvent event) {  
  25.         int action = event.getAction();  
  26.         if (null == mVelocityTracker) {  
  27.             mVelocityTracker = VelocityTracker.obtain();  
  28.         }  
  29.         mVelocityTracker.addMovement(event);  
  30.           
  31.         switch (action) {  
  32.             case MotionEvent.ACTION_DOWN:  
  33.                 //获取第一个触摸点的id  
  34.                 mPointerId = event.getPointerId(0);  
  35.                 break;  
  36.   
  37.             case MotionEvent.ACTION_MOVE:  
  38.                 mVelocityTracker.computeCurrentVelocity(1000);  
  39.                 float xVelocity = mVelocityTracker.getXVelocity(event.getPointerId(mPointerId));  
  40.                 float yVelocity = mVelocityTracker.getYVelocity(event.getPointerId(mPointerId));  
  41.                 Log.e(TAG, "xVelocity = " + xVelocity + ",yVelocity = " + yVelocity);  
  42.                 break;  
  43.   
  44.             case MotionEvent.ACTION_UP:  
  45.             case MotionEvent.ACTION_CANCEL:  
  46.                 if (null != mVelocityTracker) {  
  47.                     mVelocityTracker.recycle();  
  48.                 }  
  49.                 break;  
  50.         }  
  51.   
  52.         return super.onTouchEvent(event);  
  53.     }  
  54.   



更多相关文章

  1. Android(安卓)NDK进入发展
  2. 阿里ctf-2014 android 第一、二题
  3. Android之循环显示图像的Android(安卓)Gallery组件
  4. Android(安卓)浅谈AsyncTask异步
  5. Android(安卓)滑动冲突处理
  6. Android(安卓)Alarm定时任务基础
  7. Android获取经纬度、计算距离、方位角
  8. 五种控制Android应用的权限的方法
  9. Android(安卓)UI之布局

随机推荐

  1. 【翻译】(1)Android NDK Overview
  2. Mono for Android试用体验
  3. android布局属性之margin
  4. 自定义组件
  5. Android应用程序启动过程——Launcher源
  6. 解决Android Studio 和 Android SDK Mana
  7. 常用的android弹出对话框alertDialog
  8. android videoview 没有画面的一个原因
  9. Android系统上实现应用程序的静默安装
  10. LinearLayout和RelativeLayout