android事件分發touchevent的dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent理解

參考:https://blog.csdn.net/morgan_xww/article/details/9372285

https://www.jianshu.com/p/35a8309b9597

基礎知識

佈局可定義應用中的界面結構(例如 Activity 的界面結構)。佈局中的所有元素均使用 View 和 ViewGroup 對象的層次結構進行構建。View 通常繪製用戶可查看並進行交互的內容。然而,ViewGroup 是不可見容器,用於定義 View 和其他 ViewGroup 對象的佈局結構,如圖 1 所示。

View 對象通常稱爲“微件”,可以是衆多子類之一,例如 Button 或 TextView。
ViewGroup 對象通常稱爲“佈局”,可以是提供其他佈局結構的衆多類型之一,例如 LinearLayout 或 ConstraintLayout。

 

touch事件3個方法:
public boolean dispatchTouchEvent(MotionEvent ev);    //用來分派event;從ViewGroup往view派發
public boolean onInterceptTouchEvent(MotionEvent ev); //用來攔截event;返回true表示攔截
public boolean onTouchEvent(MotionEvent ev);          //用來處理event;處理觸控

Activity類  Activity dispatchTouchEvent();             onTouchEvent();
ViewGroup子類 FrameLayout、LinearLayout、ListView等   dispatchTouchEvent();   onInterceptTouchEvent();
onTouchEvent();
View控件 Button、TextView、EditText…… dispatchTouchEvent();
onTouchEvent();

 

dispatchTouchEvent() 用來分派事件。
其中調用了onInterceptTouchEvent()和onTouchEvent(),一般不重寫該方法
onInterceptTouchEvent() 用來攔截事件。
ViewGroup類中的源碼實現就是{return false;}表示不攔截該事件,
事件將向下傳遞(傳遞給其子View);
若手動重寫該方法,使其返回true則表示攔截,事件將終止向下傳遞,
事件由當前ViewGroup類來處理,就是調用該類的onTouchEvent()方法
 
onTouchEvent() 用來處理事件。
返回true則表示該View能處理該事件,事件將終止向上傳遞(傳遞給其父View);
返回false表示不能處理,則把事件傳遞給其父View的onTouchEvent()方法來處理

 

此處參考:https://blog.csdn.net/morgan_xww/article/details/9372285

重點掌握

touch消息種類(基礎版)

ACTION_DOWN->按下

ACTION_MOVE->移動

ACTION_UP->鬆開

dispatchTouchEvent-事件分發順序

dispatchTouchEvent比較複雜,可以按照下面這張圖分析:ViewGroup和View組成了一棵樹形結構,最頂層爲Activity的ViewGroup,下面有若干的ViewGroup節點,每個節點之下又有若干的ViewGroup節點或者View節點,依次類推。

 

 

  當一個Touch事件(ACTION_DOWN)依次下發,下發的過程是調用子View(ViewGroup)的dispatchTouchEvent方法實現的。簡單來說,就是ViewGroup遍歷它包含着的子View,調用每個View的dispatchTouchEvent方法,而當子View爲ViewGroup時,又會通過調用ViewGroup的dispatchTouchEvent方法繼續調用其內部的View的dispatchTouchEvent方法。上述例子中的消息action_down下發順序是這樣的:①-②-⑤-⑥-⑦-③-④。
  dispatchTouchEvent方法只負責事件的分發,它擁有boolean類型的返回值,當返回爲true時,(ACTION_MOVE與ACTION_UP)順序下發會中斷。在上述例子中如果⑤的dispatchTouchEvent返回結果爲true,那麼⑥-⑦-③-④將都接收不到本次Touch事件但只收到了(ACTION_DOWN)。
  ViewGroup的dispatchTouchEvent是真正在執行“分發”工作,而View的dispatchTouchEvent方法,並不執行分發工作,或者說它分發的對象就是自己,決定是否把touch事件交給自己處理,而處理的方法,便是onTouchEvent事件。

onTouchEvent-事件處理

  • 如果返回值是true,表示消費(consume)了這個事件。以ACTION_DOWN爲例,如果某個控件的onTouchEvent返回值爲true,則後續的n個ACTION_MOVE與1個ACTION_UP都會逐層(通過ViewGroup,不會再遍歷View)傳遞到這個控件的onTouchEvent進行處理。
  • 如果返回值是false,則會將ACTION_DOWN傳遞給其父ViewGroup的onTouchEvent進行處理,直到由哪一層ViewGroup消費了ACTION_DOWN事件爲止。
  •  
  • 由於觸摸事件都是連續的。如果ACTION_MOVE傳遞到子控件,而子控件的onTouchEvent返回值是false,即沒有處理該ACTION_MOVE事件,則後續的ACTION_UP就不會傳到該子控件來了。
  •  
  • 這裏要注意是逐層,也就是說每層(指的只是ViewGroup)的攔截器還是可以攔截到後續的ACTION_MOVE與ACTION_UP。如果後續的ACTION_MOVE與ACTION_UP被某層的攔截器攔截,則後續的事件將不會再傳遞給之前處理onTouchEvent的子控件,而是逐層傳遞給由攔截消息的這個控件的onTouchEvent函數進行處理,並且會向其之前接收事件的子控件發送一個ACTION_CANCEL,表示後續事件被取消了。

參考:https://www.jianshu.com/p/35a8309b9597

舉例子

佈局結構和ontouch事件的傳遞順序

長這樣:

注:XML的繪製順序是從外層到內層,同一層從上到下,繪製遲的覆蓋繪製早的;在這裏的XML,無論是否把MyButton寫在TextView後面,由於MyButton顯示優先級高於TextView所以顯示在TextView上,並且獲取事件優先級也高於TextView。

1和2點的邏輯示意圖

 

1.點白色部分FrameLayout:Frame的OntouchEvent返回false表示不消費事件;ACTION_UP就不傳給他了

引用圖片:https://blog.csdn.net/morgan_xww/article/details/9372285

2.點藍色部分RelativeLayout:RelativeLayout的OntouchEvent返回false表示不消費事件;ACTION_UP不傳給他了

由於觸摸事件都是連續的。如果ACTION_DOWN傳遞到子控件,而子控件的onTouchEvent返回值是false,即沒有處理該ACTION_DOWN事件,則後續的ACTION_MOVE和ACTION_UP就不會傳到該子控件來了。ACTION_DOWN事件一直傳遞到了RelativeLayout,但是最終是被MainActivity的onTouchEvent處理的,而從而導致ACTION_MOVE和ACTION_UP只傳遞到了MainActivity,最終也是由MainActivity處理的情況。

引用圖片:https://blog.csdn.net/morgan_xww/article/details/9372285

3.點淡綠色部分MyTextView:MyTextView返回true;ACTION_UP繼續傳給他

邏輯示意

引用圖片:https://blog.csdn.net/morgan_xww/article/details/9372285

4.點淡藍色部分MyButton:MyButton返回false;MyTextView返回true; ACTION_UP不再通過MyButton

由於觸摸事件都是連續的。如果ACTION_DOWN傳遞到子控件,而子控件的onTouchEvent返回值是false,即沒有處理該ACTION_DOWN事件,則後續的ACTION_MOVE和ACTION_UP就不會傳到該子控件來了。ACTION_DOWN事件一直傳遞到了MyButton,但是最終是被MyTextView的onTouchEvent處理的,而從而導致ACTION_MOVE和ACTION_UP只傳遞到了MyTextView,最終也是由MyTextView處理而跳過MyButton情況。

參考這個 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章