VelocityTracker使用总结

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.cpp
void 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;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/wusj3/article/details/82620248