android view滑动助手类 OverScroller VelocityTracker


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.   



你可能感兴趣的:(Android,零碎知识记录)