天天看點

Android事件分發機制詳解

事件分發機制詳解

一、基礎知識介紹

1、經常用的事件有:MotionEvent.ACTION_DOWN,MotionEvent.ACTION_MOVE,MotionEvent.ACTION_UP等

2、常用的方法有:disPatchTouchEvent(),onTouchEvent(),onInterceptTouchEvent()(隻有ViewGroup才有這個方法,View沒有這個方法,且ViewGroup是View的子類);

二、方法功能介紹

1、dispatchTouchEvent事件分發的排程者與指揮者,觸發的第一個方法

2、onInterceptTouchEvent,決定是否攔截事件:

3、如果攔截事件,調用目前控件的onTouchEvent方法,

4、如果不攔截,判斷是否有子控件,

5、onTouchEvent,決定是否消費事件,消費傳回True,不消費傳回False。如果傳回的為false,之後的事件都不會再傳遞到目前的控件了(會不再通路目前控件),如果傳回true,之後的事件依然還是會傳遞過來的。

三、各個方法和控件之間事件傳遞關系

事件傳遞流程:事件—>Activity—>Window—>DecorView—>ViewTree(嵌套在一起的各種控件)

一個事件,首先會由Activity的dispatchTouchEvent方法接受,然後分發到附着在Activity上的Window,Window不進行處理直接分發到ViewTree;最外層的ViewTop(預設為是ViewGroup類型的)會先調用自己的dispatchTouchEvent方法,然後由dispatchTouchEvent調用onInterceptTouchEvent方法,如果傳回true,調用自己的onTouchEvent方法;如果傳回false,繼續向下一個控件進行事件分發。

如果ViewTree中的所有控件都不消費,那就傳回到Activity中,由Activity調用onTouchEvent方法。

下面給大家一個具體的例子,大家可以有一個形象的感受。

四、示例Demo(示例中的代碼是不考慮下面說的特殊情況的)

布局檔案

<VP1>

<VP2>

<CustomView/>

</VP2>

</VP1>

1、控件都不消費

down事件

Log:-Activity:dispatchTouchEvent:調用

Log:-VP1:dispatchTouchEvent:調用

Log:-VP1:onInterceptTouchEvent:調用

Log:-VP1:onInterceptTouchEvent:傳回:false

Log:-VP2:dispatchTouchEvent:調用

Log:-VP2:onInterceptTouchEvent:調用

Log:-VP2:onInterceptTouchEvent:傳回:false

Log:-CustomView:dispatchTouchEvent:調用

Log:-CustomView:touchEvent:調用

Log:-CustomView:touchEvent:傳回:false

Log:-CustomView:dispatchTouchEvent:傳回:false

Log:-VP2:touchEvent:調用

Log:-VP2:touchEvent:傳回:false

Log:-VP2:dispatchTouchEvent:傳回:false

Log:-VP1:touchEvent:調用

Log:-VP1:touchEvent:傳回:false

Log:-VP1:dispatchTouchEvent:傳回:false

Log:-Activity:touchEvent:調用

Log:-Activity:touchEvent:傳回:false

Log:-Activity:dispatchTouchEvent:傳回:false

up事件

2、CustomView消費

Log:-CustomView:touchEvent:傳回:true

Log:-CustomView:dispatchTouchEvent:傳回:true

Log:-VP2:dispatchTouchEvent:傳回:true

Log:-VP1:dispatchTouchEvent:傳回:true

Log:-Activity:dispatchTouchEvent:傳回:true

Up事件

3、VP2攔截不消費

Down事件

Log:-VP2:onInterceptTouchEvent:傳回:true

UP事件

4、VP2攔截消費

Log:-VP2:touchEvent:傳回:true

五、特殊情況

1、如果disallowIntercept=true,那麼不會再走控件中的onInterceptTouchEvent方法,直接标記為不攔截事件。

2、如果有requestDisallowInterceptTouchEvent(true)方法,父類控件不走onInterceptTouchEvent方法,不用通過回調來判斷是否需要攔截事件,而是直接進行傳送。

3、這兩方面,主要是用來解決手勢沖突的。

六、小提示

1、如果滿足下列條件之一,就會調用onTouchEvent方法。

  1. 所處的view攔截了事件
  2. 沒有子View
  3. 子View都不消費事件

2、onTouchListener中的onTouch回調與dispatchTouchEvent的優先級一樣,都是優先于onTouchEvent的

繼續閱讀