在Android事件中,有幾個比較基本的概念和知識點需要掌握。比如,表示最小移動門檻值的TouchSlop,追蹤事件速度的VelocityTracker,用于檢測手勢的GestureDetector,實作View彈性滑動的Scroller,使用者幫助處理View和事件的輔助工具類ViewDragView等。這些都是使用事件、了解事件中需要掌握的知識點。本篇将簡單介紹Slop和VelocityTracker的基本知識。
前言
轉載請聲明,轉自【https://www.cnblogs.com/andy-songwei/p/11193433.html】謝謝!
在Android事件中,有幾個比較基本的概念和知識點需要掌握。比如,表示最小移動門檻值的TouchSlop,追蹤事件速度的VelocityTracker,用于檢測手勢的GestureDetector,實作View彈性滑動的Scroller,使用者幫助處理View和事件的輔助工具類ViewDragView等。這些都是使用事件、了解事件中需要掌握的知識點。本篇将簡單介紹Slop和VelocityTracker的基本知識。
一、TouchSlop
TouchSlop是一個系統常量,用于表示系統能夠識别的被認為是滑動的最小距離,也就是說當在螢幕上滑動的距離小于這個值時,系統不認為這是滑動操作。這個值和裝置有關,手機生産商可以自行設定該值。通過該值,可以過濾掉一些滑動距離太小的操作等,進而提高使用者體驗。該值儲存在檔案frameworks/base/core/res/res/values/config.xml中,如下所示:
<!-- Base "touch slop" value used by ViewConfiguration as a
movement threshold where scrolling should begin. -->
<dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
預設情況下,該值一般都是8dp。
Log.i("songzheweiwang", "TouchSlop=" + ViewConfiguration.get(this).getScaledTouchSlop());
列印log為(測試機的density=3.0):
07-15 17:02:22.382 6789-6789/com.example.demos I/songzheweiwang: TouchSlop=24
這裡我們順便看看該方法的源碼:
1 //======android.view.ViewConfiguration.java======
2 private final int mTouchSlop;
3 /**
4 * @return Distance in pixels a touch can wander before we think the user is scrolling
5 */
6 public int getScaledTouchSlop() {
7 return mTouchSlop;
8 }
9 ......
10 private ViewConfiguration(Context context) {
11 ......
12 mTouchSlop = res.getDimensionPixelSize( com.android.internal.R.dimen.config_viewConfigurationTouchSlop);
13 ......
14 }
二、VelocityTracker
該類用于速度追蹤,追蹤手指在滑動過程中的速度,包括水準方向速度和豎直方向速度。在前面的文章中介紹滑動沖突的解決方法時,就提到過通過比較水準方向速度和豎直方向速度來判斷控件的滑動方向。這裡我們簡單介紹一下擷取速度的方法。
1、初始化
進行初始化,擷取VelocityTracker執行個體,通過如下方法實作:
VelocityTracker mVelocityTracker = VelocityTracker.obtain();
其源碼如下:
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 static public VelocityTracker obtain() {
10 VelocityTracker instance = sPool.acquire();
11 return (instance != null) ? instance : new VelocityTracker(null);
12 }
可見,VelocityTracker原本有一個“池”,“池”中的執行個體用完後才會新執行個體一個。注釋中包含了很多資訊,什麼時候調用等,最好參照這個注釋說明來做。
2、添加使用者事件
由于要追蹤事件的速度,是以需要向VelocityTracker中添加事件。使用如下方式進行添加:
mVelocityTracker.addMovement(event);
源碼如下:
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 public void addMovement(MotionEvent event) {
11 if (event == null) {
12 throw new IllegalArgumentException("event must not be null");
13 }
14 nativeAddMovement(mPtr, event);
15 }
16 ......
17 private static native void nativeAddMovement(long ptr, MotionEvent event);
這方法可以在任何你希望的事件中進行調用。
3、計算速度
在擷取速度前必須先計算速度,使用方法如下:
mVelocityTracker.computeCurrentVelocity(int units);
我們在計算速度的時候,都需要指定時間機關,比如km/h,m/s等,表示在機關時間内的運動路程。這裡的units機關為ms,得到的速度表示機關時間内移動的像素數目。比如這裡參數為1000時,那麼後續獲得的速度就是,每1000ms移動的像素數。
該方法的源碼如下:
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 public void computeCurrentVelocity(int units) {
8 nativeComputeCurrentVelocity(mPtr, units, Float.MAX_VALUE);
9 }
10 ......
11 private static native void nativeComputeCurrentVelocity(long ptr, int units, float maxVelocity);
4、擷取速度
前面我們說了,在擷取速度前,一定要先計算速度。擷取速度通過如下兩個方法來完成:
float xVelocity = mVelocityTracker.getXVelocity();
float yVelocity = mVelocityTracker.getYVelocity();
這兩行代碼分别用于擷取水準方向和豎直方向的速度。我們知道,速度是有方向的,以不同的方向為标準,速度就有正負。在這裡擷取的速度,是以X軸正相反為正,即順着X軸正方向時速度為正,逆着X軸正方向時速度為負。同樣,對于豎直方向,順着Y軸正方向為正,逆着Y軸正方向為負。前面我們也說過了,這裡的速度是指,給定的時間間隔内,手指所滑過的像素數。
源碼如下:
1 /**
2 * Retrieve the last computed X velocity. You must first call
3 * {@link #computeCurrentVelocity(int)} before calling this function.
4 *
5 * @return The previously computed X velocity.
6 */
7 public float getXVelocity() {
8 return nativeGetXVelocity(mPtr, ACTIVE_POINTER_ID);
9 }
10 /**
11 * Retrieve the last computed Y velocity. You must first call
12 * {@link #computeCurrentVelocity(int)} before calling this function.
13 *
14 * @return The previously computed Y velocity.
15 */
16 public float getYVelocity() {
17 return nativeGetYVelocity(mPtr, ACTIVE_POINTER_ID);
18 }
19 ......
20 private static native float nativeGetXVelocity(long ptr, int id);
21 private static native float nativeGetYVelocity(long ptr, int id);
注釋中也明确說明了,擷取速度前,必須先計算速度。
5、重置并回收記憶體
當不再需要使用上述VelocityTracker執行個體時,需要重置并回收記憶體,使用方法如下:
mVelocityTracker.recycle();
對應源碼如下:
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 public void recycle() {
6 if (mStrategy == null) {
7 clear();
8 sPool.release(this);
9 }
10 }
11 ......
12 /**
13 * Reset the velocity tracker back to its initial state.
14 */
15 public void clear() {
16 nativeClear(mPtr);
17 }
18 ......
19 private static native void nativeClear(long ptr);
6、使用示例
這裡舉一個執行個體來示範上述方法的使用。
1 public class VelocityView extends View {
2 private static final String TAG = "songzheweiwang";
3 private VelocityTracker mVelocityTracker;
4
5 public VelocityView(Context context, @Nullable AttributeSet attrs) {
6 super(context, attrs);
7 mVelocityTracker = VelocityTracker.obtain();
8 }
9
10 @Override
11 public boolean onTouchEvent(MotionEvent event) {
12 mVelocityTracker.addMovement(event);
13 switch (event.getActionMasked()) {
14 case MotionEvent.ACTION_UP:
15 mVelocityTracker.computeCurrentVelocity(1000);
16 float xVelocity = mVelocityTracker.getXVelocity();
17 float yVelocity = mVelocityTracker.getYVelocity();
18 Log.i(TAG, "xVelocity=" + xVelocity + ";yVelocity=" + yVelocity);
19 break;
20 }
21 return true;
22 }
23
24 @Override
25 protected void onDetachedFromWindow() {
26 Log.i(TAG, "onDetachedFromWindow");
27 mVelocityTracker.recycle();
28 super.onDetachedFromWindow();
29 }
30 }
這裡隻是簡單示範這些方法的使用,僅做參考之用,讀者可以根據實際情況來使用它們。
在界面上滑動,使用完後退出該界面,列印log為:
07-16 10:15:18.951 10338-10338/com.example.demos I/songzheweiwang: xVelocity=643.2775;yVelocity=543.7565
07-16 10:15:26.406 10338-10338/com.example.demos I/songzheweiwang: onDetachedFromWindow