天天看點

android事件分發機制的詳解為什麼要使用事件分發?事件分發機制的分發和消費方向事件分發方向事件消費方向demo目錄結構demo的介紹項目的講解總結

android事件分發機制的詳解

為什麼要使用事件分發?

##在很多情況下,布局複雜的界面,由于有很多的控件重疊擺放在一起,這就出現了點選事件的重複性,在開發中經常遇到點選某個子控件,父控件的點選事件需要屏蔽掉,這時候就需要用到事件分發機制來協調處理。

事件分發機制的分發和消費方向

事件分發方向

事件分發方向:DecorView->phoneWindow->Activity->ViewGroup->View

事件消費方向

事件消費方向(自向而上):View->ViewGroup->Activity->PhoneWindow->DecorView;流程圖這裡我就不畫了,因為大家都是有一定經驗的人。

demo目錄結構

android事件分發機制的詳解為什麼要使用事件分發?事件分發機制的分發和消費方向事件分發方向事件消費方向demo目錄結構demo的介紹項目的講解總結

demo的介紹

項目結構很簡單,項目最上層的父類使用的Activity,然後用activity中包含一個ViewGroup的LinearLayout,子控件button做最後的點選事件處理,項目使用起來也比較簡單,比如LinearLayout下的有三個事件方dispatchTouchEvent(),onInterceptTouchEvent(),onTouchEvent()三個方法;在手機顯示的是設定每個方法的傳回值,通過彈出listPopwindow進行傳回值的設定,然後需要打開androidstudio日志列印點選事件的方法執行的順序和哪些方法調用。

項目的講解

在activity這個最上級的視窗中,重寫了dispatchTouchEvent()、onTouchEvent()兩個方法,這兩個方法的傳回值,暫時都繼承父類的方法,因為如果在activity的dispatchTouchEvent()方法中傳回false/true都隻會調用一次activity的dispatchTouchEvent方法,無法把事件傳遞下去了。隻會傳遞到更上級去了。

現在關鍵還是從LineaLayout控件中的方法講解

android事件分發機制的詳解為什麼要使用事件分發?事件分發機制的分發和消費方向事件分發方向事件消費方向demo目錄結構demo的介紹項目的講解總結

1.當LinearLayout控件中的dispatchTouchEvent()方法中傳回參數為“true”的時候,分别執行的是Activity中的dispatchTouchEvent方法,LinearLayout中的dispatchTouchEvent,其它的是重複列印的,是以當ViewGroup的dispatchTouchEvent方法傳回值是“true”的時候,意思不是事件繼續分發下去,而是自行處理,這和我以前了解的有些出入。

2.當LinearLayout控件中的dispatchTouchEvent方法中傳回參數為"false"的時候,如下圖所示

android事件分發機制的詳解為什麼要使用事件分發?事件分發機制的分發和消費方向事件分發方向事件消費方向demo目錄結構demo的介紹項目的講解總結

執行的順序為:Activity的dispatchTouchEvent方法,LineaLayout的dispatchTouchEvent,最後執行activity的onTouchEvent()方法;以此我們可以看出當LinearLayout的dispatchTouchEvent傳回值為“false”,不進行分發下去,也就是連onTouchEvent方法也是交給上級處理。

3.當LineaLayout的dispatchTouchEvent方法傳回值為super.dispatchTouchEvent(ev)的時候,如下圖所示

android事件分發機制的詳解為什麼要使用事件分發?事件分發機制的分發和消費方向事件分發方向事件消費方向demo目錄結構demo的介紹項目的講解總結

從上述截圖可以看出分發方法還是從activity的dispatchTouchEvent方法開始執行,再調用LineaLayout的dispatchTouchEvent方法,接着調用onInterceptTouchEvent方法,表示是否攔截目前的點選方法,如果onInterceptTouchEvent傳回的是false/super方法就表示點選事件不攔截,分發給button子控件,是以就會調用button的dispatchTouchEvent方法和onTouchEvent方法。

這時候就要考慮button中的兩個分發方法的傳回值了:

1.如果button中的dispatchTouchEvent方法中傳回true,如下圖所示:

android事件分發機制的詳解為什麼要使用事件分發?事件分發機制的分發和消費方向事件分發方向事件消費方向demo目錄結構demo的介紹項目的講解總結

走的幾個方法如下:activity的dispatchTouchEvent方法,LineaLayout的dispatchTouchEvent方法,LineaLayout的onInterceptTouchEvent方法,最後隻會執行button的dispatchTouchEvent()方法,因為button中dispatchTouchEvent傳回的參數是true,也就相當于這個事件鍊中斷了,不會再分發下去了,也不會沿上級傳遞了。

2.如果button中的dispatchTouchEvent方法中傳回false,如下圖所示:

android事件分發機制的詳解為什麼要使用事件分發?事件分發機制的分發和消費方向事件分發方向事件消費方向demo目錄結構demo的介紹項目的講解總結

前面三個方法還是一樣的執行,關鍵看後面兩個方法,先執行的是button的dispatchTouchEvent方法,因為在button的dispatchTouchEvent方法中傳回了false,表示目前的事件不分發給目前的button下的onTouchEvent方法了,是以button的onTouchEvent方法就不執行了,當時事件并沒有中斷,可以往上傳遞,是以就隻能執行button的上一級父類的onTouchEvent方法了,也就是LinearLayout的onTouchEvent方法了。

3.如果button中的dispatchTouchEvent方法中傳回super,如下圖所示:

android事件分發機制的詳解為什麼要使用事件分發?事件分發機制的分發和消費方向事件分發方向事件消費方向demo目錄結構demo的介紹項目的講解總結

同樣執行五個方法,前面三個方法和上面一樣,這時候會調用button的dispatchTouchEvent,因為是super的,是以事件預設是繼續分發下去,如果button的dispatchTouchEvent是super/true的,預設就是自己消費掉了,不會再向上級傳遞了。反之button的dispatchTouchEvent是false的,自己不完全消費掉,還是可以往上級傳遞,調用LinearLayout的onTouchEvent方法,如下圖所示:

android事件分發機制的詳解為什麼要使用事件分發?事件分發機制的分發和消費方向事件分發方向事件消費方向demo目錄結構demo的介紹項目的講解總結

項目到這,基本就差不多。很好了解把!好了多了也不說了,想了解詳情可以下載下傳下demo,自己測試一下就什麼都懂了。

連結位址:事件分發demo連結位址

總結

總之,如果一個控件中,不管是Activity還是ViewGroup,view的dispatchTouchEvent方法中傳回true,就表示事件在目前控件斷掉了,不會向上級傳遞也不會目前控件消費;一個ViewGroup/View/Activity的dispatchTouchEvent方法如果傳回false,意思就是事件不再目前的控件分發下去,就會交給上一級的父類onTouchEvent方法進行處理;一個ViewGroup的onInterceptTouchEvent攔截方法,如果傳回值為true,攔截掉目前的事件,交由自己的onTouchEvent方法或者父類的onTouchEvent方法處理,如果目前的ViewGroup的onTouchEvent方法傳回值為super/false,表示目前的控件不完全消費掉目前的點選事件,也會交由上級的onTouchEvent方法處理,反之,傳回true就隻能調用目前的ViewGroup的onTouchEvent方法,如果ViewGroup的onInterceptTouchEvent攔截方法傳回值false/super,都表示不攔截目前要傳遞的事件,事件往下級傳遞,最終如果子類的onTouchEvent方法中傳回super/true,表示事件處理完畢,整個流程結束,如果是傳回false,事件交由上一級處理,如果上一級的onTouchEvent方法中還是傳回false,繼續交由上級處理,依次類推…