關於onTouch事件的系統學習,是參考:基於源碼來了解Android的事件分發機制
個人總結:事件的分發還是基於View的視圖樹,進行遞歸遍歷
①首先在ViewGroup中,先判斷父控件(父View)是否進行攔截事件 onIntercept()。
②父View沒有攔截,在dispatchTouchEvent中遍歷子View的dispatchTouchEvent事件。
③在子View的dispatchTouchEvent事件中,判斷當前子View是否註冊了onTouchListener。
如果註冊了,就執行onTouchEvent事件。
④如果當前子View沒有註冊onTouch事件,就回到父View的dispatchTouchEvent事件中,
遍歷子View,知道遍歷完成,沒有子View去註冊onTouchListener事件,就會調用
父View的super.dispatchTouchEvent()方法,來觸發自己的監聽器。
⑤子View註冊了onTouchListener監聽器,在ACTION_DOWN中,監聽長按方法,通過一個Runnable對象,
來檢測是當前子View是否註冊了onLongClickListener監聽事件。並設置一個boolean屬性
mHasPerformLongPress = true。
⑥在當前註冊了onTouchListener的ACTION_UP方法中,根據mHasPerformLongPress = fasle;時
檢測當前子View是否註冊了onClickListener監聽。
執行順序就是:
ViewGroup : onInterceptTouchEvent > ViewGroup : dispatchTouchEvent > View : dispatchTouchEvent
> View : onTouchEvent > View : onLongClick > View : onClick
如果遍歷子View 沒有註冊onTouchListener,就調用:
ViewGroup : onInterceptTouchEvent
> ViewGroup : dispatchTouchEvent > View : dispatchTouchEvent
ViewGroup :onTouchEvent > ViewGroup : onLongClick > ViewGroup : onClick
返回true,表示當前View消費了該事件,事件不再往下傳遞。
如果父View攔截消費了該事件,就會向子View傳遞一個ev.setAction(ACTION_CANCEL);
表示父View攔截消費了該事件,也是往子View傳遞的最後一個事件ACTION_CANCEL。
Tips:關於MotionEvent的幾個API:
①ev.getX();//當前的X、Y座標是基於父佈局View的相對座標值。即在父View左上角原點的(X,Y)座標點。相對座標
ev.getY();
ev.getRawX();//當前的X、Y座標就是基於屏幕左上角原點的(X,Y)座標點。絕對座標。
ev.getRawY();
②關於View上的ACTION_DOWN,ACTION_MOVE,ACTION_UP的一系列叫做事件流。
如果當前View接收了父View視圖的ACTION_DOWN,即在ACTION_DOWN中返回true,
那麼與ACTION_DOWN 相關的事件流都要分發給當前的子視圖View。
但是,父視圖希望攔截其中的一些事件,不繼續傳遞給子視圖View,就需要給子視圖
傳遞一個ACTION_CANCEL事件。
關於多點觸控的,pointer 的
MotionEvent.ACTION_POINTER_DOWN:代表用戶的第二根手機觸碰屏幕
MotionEvent.ACTION_POINTER_UP:代表用戶多點觸控的第一個手指離開屏幕
每一個pointer都會有自己的id,index。
整個事件流中,pointer的id不會發生變化,但是index會發生變化。
int index = event.getActionIndex();
int mActivePointerId = event.getPointerId(index);
自己先對多點觸控,留個坑,不是今天學習主線。國慶十月五號補全。立個flag。