VelocityTracker的用法、原理与场景使用场景

2,081 阅读2分钟

VelocityTracker的用法、原理与场景使用场景

一. 基本使用

VelocityTracker是Android系统提供的用于追踪手指滑动速度的类,包括水平方向和垂直方向,

// 获取tracker对象
VelocityTracker velocityTracker= VelocityTracker.obtain() ;
// 添加监听对象,一般是MotionEvent
velocityTracker.addMovement(event);
// 设置时间单位,units:设置为1,表示1毫秒时间单位内运动了多少个像素;
// 设置为1000,表示1秒时间单位内运动了多少个像素。
 
velocityTracker.computeCurrentVelocity(int units,float maxVelocity);
// 获取x方向(水平)的速度
int xVelocity = (int) velocityTracker.getXVelocity();
// 获取Y方向(垂直)的速度
int yVelocity = (int) velocityTracker.getYVelocity();

// 在手指抬起(ACTION_UP)或者事件取消(ACTION_CANCEL)的时候,调用下面的函数
recycle();

二. 常见使用场景

场景1:Fling效果,典型应用如RecyclerView,GestureDetector

RecyclerView.java

@Override
public boolean onTouchEvent(MotionEvent e) {
     ....

    if (mVelocityTracker == null) {
        mVelocityTracker = VelocityTracker.obtain();
    }
    boolean eventAddedToVelocityTracker = false;
    switch (action) {
        case MotionEvent.ACTION_DOWN: {
            ......
            mScrollPointerId = e.getPointerId(0);
            ......
        }
        break;
        case MotionEvent.ACTION_MOVE: {
            ......
        break;
        case MotionEvent.ACTION_UP: {
            mVelocityTracker.addMovement(vtev);
            eventAddedToVelocityTracker = true;
            mVelocityTracker.computeCurrentVelocity(1000, mMaxFlingVelocity);
            // 计算手指滑动 X/Y方向上的速度
            final float xvel = canScrollHorizontally
                    ? -mVelocityTracker.getXVelocity(mScrollPointerId) : 0;
            final float yvel = canScrollVertically
                    ? -mVelocityTracker.getYVelocity(mScrollPointerId) : 0;
            // 使用X、Y方向上的速度,计算fling的距离
            if (!((xvel != 0 || yvel != 0) && fling((int) xvel, (int) yvel))) {
                setScrollState(SCROLL_STATE_IDLE);
            }
            resetScroll();
        }
        break;
        case MotionEvent.ACTION_CANCEL: {
            cancelScroll();
        }
        break;
    }
    if (!eventAddedToVelocityTracker) {
        mVelocityTracker.addMovement(vtev);
    }
    vtev.recycle();

    return true;
}

三. 实现原理

我们从该类最关键的两个函数computeCurrentVelocity()和getVelocity(getXVelocity和getXVelocity底层调用的是此函数)着手分析下.

/**
 * Compute the current velocity based on the points that have been
 * collected.  Only call this when you actually want to retrieve velocity
 * information, as it is relatively expensive.  You can then retrieve
 * the velocity with {@link #getXVelocity()} and
 * {@link #getYVelocity()}.
 *
 * @param units The units you would like the velocity in.  A value of 1
 * provides pixels per millisecond, 1000 provides pixels per second, etc.
 * @param maxVelocity The maximum velocity that can be computed by this method.
 * This value must be declared in the same unit as the units parameter. This value
 * must be positive.
 */
public void computeCurrentVelocity(int units, float maxVelocity) {
    nativeComputeCurrentVelocity(mPtr, units, maxVelocity);
}
/**
 * Retrieve the last computed X velocity.  You must first call
 * {@link #computeCurrentVelocity(int)} before calling this function.
 *
 * @param id Which pointer's velocity to return.
 * @return The previously computed X velocity.
 */
public float getXVelocity(int id) {
    return nativeGetXVelocity(mPtr, id);
}

/**
 * Retrieve the last computed Y velocity.  You must first call
 * {@link #computeCurrentVelocity(int)} before calling this function.
 *
 * @param id Which pointer's velocity to return.
 * @return The previously computed Y velocity.
 */
public float getYVelocity(int id) {
    return nativeGetYVelocity(mPtr, id);
}

调用的是JNI层文件实现具体功能,

Image_20230301163707.png

Image_20230301165208.png