Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android 事件分發機制(圖文詳解)

android 事件分發機制(圖文詳解)

編輯:關於Android編程

在Android開發中,事件分發機制是一塊Android比較重要的知識體系,了解並熟悉整套的分發機制有助於更好的分析各種點擊滑動失效問題,更好去擴展控件的事件功能和開發自定義控件,同時事件分發機制也是Android面試必問考點之一,如果你能把下面的一些事件分發圖當場畫出來肯定加分不少。廢話不多說,總結一句:事件分發機制很重要。

Android 事件分發流

關於Android 事件分發機制網上的博文很多,但是很多都是寫個Demo然後貼一下輸出的Log或者拿源碼分析,然後一堆的注釋和說明,如果用心的去看肯定是收獲不少但是確實很難把整個流程說清和記住。曾經也是拼命想記住整個流程,但是一段時間又忘了,最後覺得分析這種問題和事件流的走向,一張圖來解釋和說明會清晰很多,下面我根據畫的一張事件分發流程圖,說明的事件從用戶點擊之後,在不同函數不同返回值的情況的最終走向。

圖 1.
注:

仔細看的話,圖分為3層,從上往下依次是Activity、ViewGroup、View
事件從左上角那個白色箭頭開始,由Activity的dispatchTouchEvent做分發
箭頭的上面字代表方法返回值,(return true、return false、return super.xxxxx(),super 的意思是調用父類實現。
dispatchTouchEvent和 onTouchEvent的框裡有個【true—->消費】的字,表示的意思是如果方法返回true,那麼代表事件就此消費,不會繼續往別的地方傳了,事件終止。
目前所有的圖的事件是針對ACTION_DOWN的,對於ACTION_MOVE和ACTION_UP我們最後做分析。
之前圖中的Activity 的dispatchTouchEvent 有誤(圖已修復),只有return super.dispatchTouchEvent(ev) 才是往下走,返回true 或者 false 事件就被消費了(終止傳遞)。
仔細看整個圖,我們得出事件流 走向的幾個結論(希望讀者專心的看下圖 1,多看幾遍,腦子有比較清晰的概念。)
1、如果事件不被中斷,整個事件流向是一個類U型圖,我們來看下這張圖,可能更能理解U型圖的意思。

這裡寫圖片描述
圖 2.
所以如果我們沒有對控件裡面的方法進行重寫或更改返回值,而直接用super調用父類的默認實現,那麼整個事件流向應該是從Activity—->ViewGroup—>View 從上往下調用dispatchTouchEvent方法,一直到葉子節點(View)的時候,再由View—>ViewGroup—>Activity從下往上調用onTouchEvent方法。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjKhojxzdHJvbmc+ZGlzcGF0Y2hUb3VjaEV2ZW50ILrNIG9uVG91Y2hFdmVudCDSu7WpcmV0dXJuIHRydWUsysK8/r7NzaPWubSrtd3By6Ootb2079bVteOjqaOow7vT0MutxNzU2crVtb3V4rj2ysK8/qOpoaO/tM/CzbzW0Na70qpyZXR1cm4gdHJ1ZcrCvP6+zcO71Nm8zND4tKvPwsilwcujrLbU09pyZXR1cm4gdHJ1Zc7Sw8e+rbOjy7XKwrz+sbvP+7fRwcujrM/7t9HBy7XE0uLLvL7NysfKwrz+19+1vdXiwO++zcrH1tW146Ossru74c35z8K0q6Osw7vT0MutxNzU2crVtb3V4rj2ysK8/sHLoaM8L3N0cm9uZz48L3A+DQo8cD48YnIgLz4NCs28IDMuPC9wPg0KPHA+M6GiPHN0cm9uZz5kaXNwYXRjaFRvdWNoRXZlbnQgus0gb25Ub3VjaEV2ZW50IHJldHVybiBmYWxzZbXEyrG68srCvP62vLvYtKu4+Li4v9i8/rXEb25Ub3VjaEV2ZW50tKbA7aGjPC9zdHJvbmc+PC9wPg0KPHA+PGJyIC8+DQrNvCA0LjwvcD4NCjxwPr+0yc/NvMnuwLbJq7XEz9+jrLbU09q3tbvYZmFsc2W1xMfpv/ajrMrCvP62vMrHtKu4+Li4v9i8/m9uVG91Y2hFdmVudLSmwO2hozwvcD4NCjxwPrbU09pkaXNwYXRjaFRvdWNoRXZlbnQgt7W72CBmYWxzZSC1xLqs0uXTprjDysejusrCvP7No9a5zfnX01ZpZXe0q7Xdus231reizazKsb+qyrzN+bi4v9i8/rvYy92jqLi4v9i8/rXEb25Ub3VjaEV2ZW50v6rKvLTTz8LN+cnPu9i0q9axtb3Es7j2b25Ub3VjaEV2ZW50IHJldHVybiB0cnVlo6mjrMrCvP631reiu/rWxr7Nz/G13bnpo6xyZXR1cm4gZmFsc2UgtcTS4tLlvs3Kx7XduenNo9a5yLu687+qyry72MvdoaM8YnIgLz4NCrbU09pvblRvdWNoRXZlbnQgcmV0dXJuIGZhbHNlIL7Nsci9z7zytaXBy6Osy/y+zcrHsrvP+7fRysK8/qOssqLIw8rCvP68zND4zfm4uL/YvP61xLe9z/K008/CzfnJz8H3tq+hozxiciAvPg0KNKGiKipkaXNwYXRjaFRvdWNoRXZlbnShom9uVG91Y2hFdmVudKGib25JbnRlcmNlcHRUb3VjaEV2ZW50PGJyIC8+DQpWaWV3R3JvdXAgus1WaWV3tcTV4tCpt723qLXExKzIz8q1z9a+zcrHu+HIw9X7uPbKwrz+sLLXsFXQzc3q1fvX383qo6zL+dLUIHJldHVybiBzdXBlci54eHh4eHgoKSC+zbvhyMPKwrz+0sDV1VXQzbXEt73P8rXEzerV+9ffzerV+7j2ysK8/sH3tq/Ct762o6mjrNbQvOSyu9f2yM66zrjEtq+jrLK7u9jL3aGisrvW1da5o6zDv7j2u7e92ra819+1vaGjKio8L3A+DQo8cD48YnIgLz4NClBhc3RlX0ltYWdlLnBuZzwvcD4NCjxwPsv50tTI57n7v7S1vbe9t6hyZXR1cm4gc3VwZXIueHh4eHgoKSDEx8O0ysK8/rXEz8LSu7j2wffP8r7NysfX31XQzc/C0ru49sS/seqjrMnUzqK8x9ehyc/D5tXi1cXNvKOsxOO+zcTcuty/7MXQts+z9s/C0ru49tffz/LKx8TEuPa/2Lz+tcTExLj2uq/K/aGjPGJyIC8+DQo1oaJvbkludGVyY2VwdFRvdWNoRXZlbnQgtcTX99PDPC9wPg0KPHA+PGltZyBhbHQ9"這裡寫圖片描述" src="http://upload-images.jianshu.io/upload_images/966283-403f6e8b820f71f1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" title="\" />
圖 5.
Intercept 的意思就攔截,每個ViewGroup每次在做分發的時候,問一問攔截器要不要攔截(也就是問問自己這個事件要不要自己來處理)如果要自己處理那就在onInterceptTouchEvent方法中 return true就會交給自己的onTouchEvent的處理,如果不攔截就是繼續往子控件往下傳。默認是不會去攔截的,因為子View也需要這個事件,所以onInterceptTouchEvent攔截器return super.onInterceptTouchEvent()和return false是一樣的,是不會攔截的,事件會繼續往子View的dispatchTouchEvent傳遞。

6、ViewGroup 和View 的dispatchTouchEvent方法返回super.dispatchTouchEvent()的時候事件流走向。


圖 6
首先看下ViewGroup 的dispatchTouchEvent,之前說的return true是終結傳遞。return false 是回溯到父View的onTouchEvent,然後ViewGroup怎樣通過dispatchTouchEvent方法能把事件分發到自己的onTouchEvent處理呢,return true和false 都不行,那麼只能通過Interceptor把事件攔截下來給自己的onTouchEvent,所以ViewGroup dispatchTouchEvent方法的super默認實現就是去調用onInterceptTouchEvent,記住這一點。
那麼對於View的dispatchTouchEvent return super.dispatchTouchEvent()的時候呢事件會傳到哪裡呢,很遺憾View沒有攔截器。但是同樣的道理return true是終結。return false 是回溯會父類的onTouchEvent,怎樣把事件分發給自己的onTouchEvent 處理呢,那只能return super.dispatchTouchEvent,View類的dispatchTouchEvent()方法默認實現就是能幫你調用View自己的onTouchEvent方法的。

說了這麼多,不知道有說清楚沒有,我這邊最後總結一下:

**對於 dispatchTouchEvent,onTouchEvent,return true是終結事件傳遞。return false 是回溯到父View的onTouchEvent方法。
ViewGroup 想把自己分發給自己的onTouchEvent,需要攔截器onInterceptTouchEvent方法return true 把事件攔截下來。
ViewGroup 的攔截器onInterceptTouchEvent 默認是不攔截的,所以return super.onInterceptTouchEvent()=return false;
View 沒有攔截器,為了讓View可以把事件分發給自己的onTouchEvent,View的dispatchTouchEvent默認實現(super)就是把事件分發給自己的onTouchEvent。**
ViewGroup和View 的dispatchTouchEvent 是做事件分發,那麼這個事件可能分發出去的四個目標

注:——> 後面代表事件目標需要怎麼做。
1、 自己消費,終結傳遞。——->return true ;
2、 給自己的onTouchEvent處理——-> 調用super.dispatchTouchEvent()系統默認會去調用 onInterceptTouchEvent,在onInterceptTouchEvent return true就會去把事件分給自己的onTouchEvent處理。
3、 傳給子View——>調用super.dispatchTouchEvent()默認實現會去調用 onInterceptTouchEvent 在onInterceptTouchEvent return false,就會把事件傳給子類。
4、 不傳給子View,事件終止往下傳遞,事件開始回溯,從父View的onTouchEvent開始事件從下到上回歸執行每個控件的onTouchEvent——->return false;
注: 由於View沒有子View所以不需要onInterceptTouchEvent 來控件是否把事件傳遞給子View還是攔截,所以View的事件分發調用super.dispatchTouchEvent()的時候默認把事件傳給自己的onTouchEvent處理(相當於攔截),對比ViewGroup的dispatchTouchEvent 事件分發,View的事件分發沒有上面提到的4個目標的第3點。
ViewGroup和View的onTouchEvent方法是做事件處理的,那麼這個事件只能有兩個處理方式:

1、自己消費掉,事件終結,不再傳給誰—–>return true;
2、繼續從下往上傳,不消費事件,讓父View也能收到到這個事件—–>return false;View的默認實現是不消費的。所以super==false。
ViewGroup的onInterceptTouchEvent方法對於事件有兩種情況:

1、攔截下來,給自己的onTouchEvent處理—>return true;
2、不攔截,把事件往下傳給子View—->return false,ViewGroup默認是不攔截的,所以super==false;

關於ACTION_MOVE 和 ACTION_UP

上面講解的都是針對ACTION_DOWN的事件傳遞,ACTION_MOVE和ACTION_UP在傳遞的過程中並不是和ACTION_DOWN 一樣,你在執行ACTION_DOWN的時候返回了false,後面一系列其它的action就不會再得到執行了。簡單的說,就是當dispatchTouchEvent在進行事件分發的時候,只有前一個事件(如ACTION_DOWN)返回true,才會收到ACTION_MOVE和ACTION_UP的事件。具體這句話很多博客都說了,但是具體含義是什麼呢?我們來看一下下面的具體分析。

上面提到過了,事件如果不被打斷的話是會不斷往下傳到葉子層(View),然後又不斷回傳到Activity,dispatchTouchEvent 和 onTouchEvent 可以通過return true 消費事件,終結事件傳遞,而onInterceptTouchEvent 並不能消費事件,它相當於是一個分叉口起到分流導流的作用,ACTION_MOVE和ACTION_UP 會在哪些函數被調用,之前說了並不是哪個函數收到了ACTION_DOWN,就會收到 ACTION_MOVE 等後續的事件的。
下面通過幾張圖看看不同場景下,ACTION_MOVE事件和ACTION_UP事件的具體走向並總結一下規律。

1、**我們在ViewGroup1 的dispatchTouchEvent 方法返回true消費這次事件

ACTION_DOWN 事件從(Activity的dispatchTouchEvent)——–> (ViewGroup1 的dispatchTouchEvent) 後結束傳遞,事件被消費(如下圖紅色的箭頭代碼ACTION_DOWN 事件的流向)。**

//打印日志
Activity | dispatchTouchEvent --> ACTION_DOWN 
ViewGroup1 | dispatchTouchEvent --> ACTION_DOWN
---->消費

這裡寫圖片描述
在這種場景下ACTION_MOVE和ACTION_UP 將如何呢,看下面的打出來的日志

Activity | dispatchTouchEvent --> ACTION_MOVE 
ViewGroup1 | dispatchTouchEvent --> ACTION_MOVE
----
TouchEventActivity | dispatchTouchEvent --> ACTION_UP 
ViewGroup1 | dispatchTouchEvent --> ACTION_UP

下圖中
紅色的箭頭代表ACTION_DOWN 事件的流向
藍色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向
這裡寫圖片描述

2、我們在ViewGroup2 的dispatchTouchEvent 返回true消費這次事件

Activity | dispatchTouchEvent --> ACTION_DOWN 
ViewGroup1 | dispatchTouchEvent --> ACTION_DOWN
ViewGroup1 | onInterceptTouchEvent --> ACTION_DOWN
ViewGroup2 | dispatchTouchEvent --> ACTION_DOWN
---->消費
Activity | dispatchTouchEvent --> ACTION_MOVE 
ViewGroup1 | dispatchTouchEvent --> ACTION_MOVE
ViewGroup1 | onInterceptTouchEvent --> ACTION_MOVE
ViewGroup2 | dispatchTouchEvent --> ACTION_MOVE
----
TouchEventActivity | dispatchTouchEvent --> ACTION_UP 
ViewGroup1 | dispatchTouchEvent --> ACTION_UP
ViewGroup1 | onInterceptTouchEvent --> ACTION_UP
ViewGroup2 | dispatchTouchEvent --> ACTION_UP
----

紅色的箭頭代表ACTION_DOWN 事件的流向
藍色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向


Paste_Image.png
3、**我們在View 的dispatchTouchEvent 返回true消費這次事件
這個我不就畫圖了,效果和在ViewGroup2 的dispatchTouchEvent return true的差不多,同樣的收到ACTION_DOWN 的dispatchTouchEvent函數都能收到 ACTION_MOVE和ACTION_UP。**
所以我們就基本可以得出結論如果在某個控件的dispatchTouchEvent 返回true消費終結事件,那麼收到ACTION_DOWN 的函數也能收到 ACTION_MOVE和ACTION_UP。

4、我們在View 的onTouchEvent 返回true消費這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向

5、我們在ViewGroup 2 的onTouchEvent 返回true消費這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向

 

6、我們在ViewGroup 1 的onTouchEvent 返回true消費這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向

7、我們在Activity 的onTouchEvent 返回true消費這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向

8、我們在View的dispatchTouchEvent 返回false並且Activity 的onTouchEvent 返回true消費這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向

9、我們在View的dispatchTouchEvent 返回false並且ViewGroup 1 的onTouchEvent 返回true消費這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向

10、我們在View的dispatchTouchEvent 返回false並且在ViewGroup 2 的onTouchEvent 返回true消費這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向
這裡寫圖片描述

11、我們在ViewGroup2的dispatchTouchEvent 返回false並且在ViewGroup1 的onTouchEvent返回true消費這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向
這裡寫圖片描述

12、我們在ViewGroup2的onInterceptTouchEvent 返回true攔截此次事件並且在ViewGroup 1 的onTouchEvent返回true消費這次事件。
紅色的箭頭代表ACTION_DOWN 事件的流向
藍色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向
這裡寫圖片描述

一下子畫了好多圖,還有好幾種情況就不再畫了,相信你也看出規律了,對於在onTouchEvent消費事件的情況:在哪個View的onTouchEvent 返回true,那麼ACTION_MOVE和ACTION_UP的事件從上往下傳到這個View後就不再往下傳遞了,而直接傳給自己的onTouchEvent 並結束本次事件傳遞過程。

對於ACTION_MOVE、ACTION_UP總結:ACTION_DOWN事件在哪個控件消費了(return true), 那麼ACTION_MOVE和ACTION_UP就會從上往下(通過dispatchTouchEvent)做事件分發往下傳,就只會傳到這個控件,不會繼續往下傳,如果ACTION_DOWN事件是在dispatchTouchEvent消費,那麼事件到此為止停止傳遞,如果ACTION_DOWN事件是在onTouchEvent消費的,那麼會把ACTION_MOVE或ACTION_UP事件傳給該控件的onTouchEvent處理並結束傳遞。

原文鏈接:http://www.jianshu.com/p/e99b5e8bd67b

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved