Android 之在View以及ViewGroup中Touch事件傳遞

關於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。


發佈了30 篇原創文章 · 獲贊 3 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章