VelocityTracker

来源:互联网 发布:linux socket pthread 编辑:程序博客网 时间:2024/05/09 15:51

VelocityTracker是android提供的用来记录滑动速度的一个类,可以监控手指移动的速度。

基本用法

如果我们想监控一个view内,手指移动的瞬时速度,该如何做?代码如下所示。主要是在onTouchEvent里记录各个MotionEvent,down事件是起点,此时需要初始化mVelocityTracker(obtain或者reset),第一次肯定是obtain。然后把当前的event记录起来(addMovement)。接着在move的时候获取速度,获取速度用mVelocityTracker.getXVelocity()或者mVelocityTracker.getYVelocity()。在调用这个之前必须做一次计算,也就是mVelocityTracker.computeCurrentVelocity(1000);

最后在up的时候要对mVelocityTracker进行recycle。很简单吧。

public class XView extends View {    private static final String DEBUG_TAG = "Velocity";        private VelocityTracker mVelocityTracker = null;    @Override    public boolean onTouchEvent(MotionEvent event) {        int index = event.getActionIndex();        int action = event.getActionMasked();        switch(action) {            case MotionEvent.ACTION_DOWN:                if(mVelocityTracker == null) {                    // Retrieve a new VelocityTracker object to watch the velocity of a motion.                    mVelocityTracker = VelocityTracker.obtain();                }                else {                    // Reset the velocity tracker back to its initial state.                    mVelocityTracker.clear();                }                // Add a user's movement to the tracker.                mVelocityTracker.addMovement(event);                break;            case MotionEvent.ACTION_MOVE:                mVelocityTracker.addMovement(event);                // When you want to determine the velocity, call                 // computeCurrentVelocity(). Then call getXVelocity()                 // and getYVelocity() to retrieve the velocity for each pointer ID.                 mVelocityTracker.computeCurrentVelocity(1000);                // Log velocity of pixels per second                // Best practice to use VelocityTrackerCompat where possible.                Log.d("", "X velocity: " +                        mVelocityTracker.getXVelocity());                Log.d("", "Y velocity: " +                        mVelocityTracker.getYVelocity());                break;            case MotionEvent.ACTION_UP:            case MotionEvent.ACTION_CANCEL:                // Return a VelocityTracker object back to be re-used by others.                mVelocityTracker.recycle();                break;        }        return true;    }}

computeCurrentVelocity

我们看下computeCurrentVelocity这个函数,有2个重载
  public void computeCurrentVelocity(int units) {      nativeComputeCurrentVelocity(mPtr, units, Float.MAX_VALUE);  }  public void computeCurrentVelocity(int units, float maxVelocity) {      nativeComputeCurrentVelocity(mPtr, units, maxVelocity);  }
    我们刚才用的是第一种方法,传了个1000.这个表示计算过去1000ms(即1s)内的速度。这个速度其实就是 ((当前的位置)-(之前的位置))/时间.如果得到的值为200就表示这1000ms内,X方向移动了200像素。
    速度是有正负的,右划就是正的,左划就是负的,上划为负,下划为正。
    最大速度传的是Float的最大值,第二种方法可以指定最大速度。这个最大速度有什么用呢?
    实际上是一个上限,比如我们当前速度300,但是上限为200,那用getXVelocity()得到的值就是200,不可能超过上限(无论正负),相关代码如下所示。
    //android_view_VelocityTracker.cppvoid VelocityTrackerState::computeCurrentVelocity(int32_t units, float maxVelocity) {    BitSet32 idBits(mVelocityTracker.getCurrentPointerIdBits());    mCalculatedIdBits = idBits;    for (uint32_t index = 0; !idBits.isEmpty(); index++) {        uint32_t id = idBits.clearFirstMarkedBit();        float vx, vy;        mVelocityTracker.getVelocity(id, &vx, &vy);        vx = vx * units / 1000;        vy = vy * units / 1000;        if (vx > maxVelocity) {            vx = maxVelocity;        } else if (vx < -maxVelocity) {            vx = -maxVelocity;        }        if (vy > maxVelocity) {            vy = maxVelocity;        } else if (vy < -maxVelocity) {            vy = -maxVelocity;        }        Velocity& velocity = mCalculatedVelocity[index];        velocity.vx = vx;        velocity.vy = vy;    }}

惯性滑动

还有个比较常见的需求,比如我们右划了一下,view往右移动,我们希望在手指抬起来之后,view能够按照惯性继续滑动一段距离然后停止,此时就需要手指抬起的时候的速度,可以在up的时候计算。

模板写法

我查了下网上的资料,发现不同的人有不同的写法,有点茫然,不知道该参考谁,本文的例子主要从android官方demo和源码内提取出来,应该没有坑,下次有需求,抄这段代码比较合适.这个写法和前文 基本用法里的有点区别,都是靠谱的,这里没有用到clear,每次都是obtain,然后recycle。基本用法里多了个clear,按道理提高了重用性,性能会好一些。但是我看了下ScrollView和ViewPager都是按照下边的写法来的,估计他们写的也比较随意。
public class XView extends View {    private static final String DEBUG_TAG = "Velocity";    private static final int V_CONSTANT=50;    private VelocityTracker mVelocityTracker = null;    @Override    public boolean onTouchEvent(MotionEvent event) {        int index = event.getActionIndex();        int action = event.getActionMasked();        initVelocityTrackerIfNotExists();        switch(action) {            case MotionEvent.ACTION_DOWN:                if(mVelocityTracker == null) {                    // Retrieve a new VelocityTracker object to watch the velocity of a motion.                    mVelocityTracker = VelocityTracker.obtain();                }                else {                    // Reset the velocity tracker back to its initial state.                    mVelocityTracker.clear();                }                // Add a user's movement to the tracker.                mVelocityTracker.addMovement(event);                break;            case MotionEvent.ACTION_MOVE:                mVelocityTracker.addMovement(event);                break;            case MotionEvent.ACTION_UP:            case MotionEvent.ACTION_CANCEL:                final VelocityTracker velocityTracker = mVelocityTracker;                velocityTracker.computeCurrentVelocity(1000);                int initialVelocity = (int) velocityTracker.getYVelocity();                if ((Math.abs(initialVelocity) > V_CONSTANT)) {                    //速度够大,就做什么事,比如翻页,some是个常数,大约在30-100之间//                    ...                } else{//                    ...                }                recycleVelocityTracker();                break;        }        return true;    }    private void initVelocityTrackerIfNotExists() {        if (mVelocityTracker == null) {            mVelocityTracker = VelocityTracker.obtain();        }    }    private void recycleVelocityTracker() {        if (mVelocityTracker != null) {            mVelocityTracker.recycle();            mVelocityTracker = null;        }    }}






0 0