View的事件體系-View基礎知識
位置引數
View的位置主要由它的四個頂點來決定,分別對應於View的四個屬性:top、left、right、bottom.
其中top是左上角的縱座標,left是左上角的橫座標,right是右下角的橫座標,bottom是右下角的縱座標.(注:這些座標都是相對於父容器所說,為相對座標)

image.png
View的寬高和座標的關係:
width = right - left; height = bottom - top;
在程式碼中獲取四個位置引數:
top = getTop(); left = getLeft(); right = getRight(); bottom = getBottom();
從3.0之後開始,Android增加了幾個引數:x、y、translationX、translationY,並且都是相對父容器的的座標,其中x和y是View左上角的座標.translationX和translationY是View左上角相對於父容器的偏移量,且預設值都為0.
left = x - translationX; top = y - translationY;
注:在View的平移過程中,top和left始終表示的是其原始左上角的位置資訊,不會發生改變,改變的是x、y、translationX和translationY.
MotionEvent
典型事件
手指接觸屏幕後所產生的一系列事件中,比較重要的有:
- ACTION_DOWN 手指剛接觸螢幕
- ACTION_MOVE 手指在螢幕上移動
- ACTION_UP 手指抬起的一瞬間
常見事件序列
- 點選屏幕後抬起 DOWN -> UP
- 點選屏幕後滑動後再抬起 DOWN -> MOVE -> UP
事件資訊
通過MotionEvent物件我們可以得到點選事件發生的x和y座標.
- getX()、getY() 相對於當前View左上角.
- getRaw()、getY() 相對於手機螢幕左上角
TouchSlop
什麼是TouchSlop
TouchSlop是系統所能識別出的最小滑動距離.如果手指在螢幕上滑動小於該距離則系統無法將該動作認定為滑動.
這是一個常量,與裝置有關,在不同的裝置上這個值可能不同.
獲取TouchSlop
int touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
使用場景
當我們在處理滑動時,可以使用這個常量來進行過濾,當滑動距離小於該值,我們可以認為未達到滑動距離的臨界值,不認為它是一次有效的滑動.
VelocityTracker
速度追蹤,用於追蹤手指在滑動過程中的速度,包括水平速度和豎直方向的速度.
使用過程
在View的onTouchEvent方法中追蹤當前單擊事件的的速度:
@Override public boolean onTouchEvent(MotionEvent event) { VelocityTracker tracker = VelocityTracker.obtain(); tracker.addMovement(event); tracker.computeCurrentVelocity(1000);//一個時間單元或時間間隔,單位為毫秒 float xVelocity = tracker.getXVelocity(); float yVelocity = tracker.getYVelocity(); return super.onTouchEvent(event); }
注:獲取速度之前必須先計算速度,即getXVelocity和getYVelocity之前必須要呼叫computeCurrentVelocity方法.這裡的速度是指一段時間內手指所滑過的畫素數,比如將時間設定為1000ms時,在1s內,手指在水平方向從左向右滑過100畫素,那麼水平速度就是100.且速度可以為負數,當手指從右向左滑動時,水平方向速度即為負值.
計算公式:
速度 = (終點位置 - 起點位置) / 時間段
當不需要使用後需重置回收.
tracker.clear(); tracker.recycle();
GestureDetector
手勢檢測,用於輔助檢測使用者的單擊、滑動、長按、雙擊等行為.
使用方式
建立GestureDetector物件並實現OnGestureListener介面,如果需要監聽雙擊行為還可以實現OnDoubleTapListener介面.並接管onTouchEvent方法.
public class SeanView extends View implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener { GestureDetector detector = new GestureDetector(this); detector.setIsLongpressEnabled(false);//解決長按屏幕後無法拖動問題 @Override public boolean onTouchEvent(MotionEvent event) { boolean consume = detector.onTouchEvent(event); return consume; } }
方法介紹
- OnGestureListener
- onDown 手指接觸螢幕的瞬間
- onShowPress 手指接觸螢幕的瞬間,尚未鬆開或拖動
- onSingleTapUp 單擊
- onScroll 拖動
- onLongPress 長按
- onFling 快速滑動
- OnDoubleTapListener
- onDoubleTap 雙擊 與onSingleTapConfirmed互斥
- onSingleTapConfirmed 單擊且後續無單擊行為
- onDoubleTapEvent 雙擊
Scroller
用於實現View的彈性滑動.Scroller本身無法讓View彈性滑動,它需要和computeScroll方法配合使用.
private Scroller scroller = new Scroller(getContext()); private void smoothScrollTo(int destX, int destY) { int scrollX = getScrollX(); int delta = destX - scrollX; scroller.startScroll(scrollX, 0, delta, 1000); invalidate(); } @Override public void computeScroll() { if (scroller.computeScrollOffset()) { scrollTo(scroller.getCurrX(), scroller.getCurrY()); postInvalidate(); } }