banner
jzman

jzman

Coding、思考、自觉。
github

Android事件分發流程分析

PS:不要太過焦慮,踏踏實實充實自己才是最重要的。

上篇文章中主要針對 Activity、ViewGroup 以及 View 中的相關事件方法進行了基本概述,下面主要以案例的方式對 Android 中的事件傳遞進行歸納。

  1. 默認的事件分發流程
  2. 事件分發
  3. 事件處理
  4. 事件攔截
  5. 總結

默認的事件分發流程#

Android 事件分發的正常流程,也就是默認情況下事件是如何分發的,首先自定義 ViewGroup 和 自定義 View, 如繼承 LinearLayout 自定義 ViewGroup 為 MLinearLayout,繼承 TextView 自定義 View 為 MTextView,然後分別重寫各自與事件分發相關的事件方法,Activity 也重寫自己的事件方法,根據日誌觀察正常的事件分發流程,佈局如下圖所示:

image

通過觸發 MTextView 的 onTouch 事件,對各個事件分發方法都默認處理,執行流程如下圖所示:

image

顯然,事件分發的起點是 Activity 的 dispatchTouchEvebt () 方法,然後通過一系列動作事件向 ViewGroup 分發,具體表現就是調用 ViewGroup 的 dispatchTouchEvebt () 方法,ViewGroup 的 onInterceptTouchEvent () 方法默認返回 false,也就是默認不攔截事件向子 View (ViewGroup 也是子 View,如 MRelativeLayout),然後,一直向下分發直到最內層的子 View 為止。

當然,事件分發至子 View , 也就是調用子 View 的 dispatchTouchEvebt () 方法,其事件分發方法內部調用了 onTouchEvent () 方法,onTouchEvent () 默認返回 false,表示該 View 不消費事件,反之返回 true 則消費該事件,下面是根據上述執行結果繪製的默認的事件分發流程,如下圖所示:

image

通過上面的驗證,至少能夠了解各個事件相關方法的執行順序咯。

事件分發#

dispatchTouchEvent () 方法負責事件的分發,決定當前事件是自身消費還是繼續向子 View 分發,返回 true,表示事件已經被消費,後續的事件也會繼續執行,如 ACTION_MOVE、ACTION_UP 等事件,返回 false 則繼續向子 View 分發事件,如果是子 View 是 ViewGroup,則先將事件分發給 onInterceptTouchEvent () 方法,從而決定是否攔截該事件。按照上面的案例將 MRelativeLayout 的 dispatchTouchEvent () 方法返回 true , 事件消費且接受之後的一系列事件,日誌截圖如下圖所示:

image

顯然,當 MRelativeLayout 的 dispatchTouchEvent () 方法返回 true 的時候,事件沒有向下傳遞,這裡為了更清楚的觀察各個事件方法的執行,具體的事件(如 ACTION_DOWN 等)沒有輸出在日誌中,所以,當 dispatchTouchEvent () 方法返回 true 時表示事件已消費。

事件攔截#

onInterceptTouchEvent () 方法負責事件的攔截,其返回值決定是否對當前事件進行攔截,返回值為 true,表示攔截當前事件,反之不攔截事件,也就是默認實現繼續調用子 View 的 dispatchTouchEvent () 方法進行事件的分發,按照上面的案列將 MRelativeLayout 的 onInterceptTouchEvent () 方法返回值設為 true,攔截當前事件,使事件不在向下傳遞,日誌截圖如下圖所示:

image

話說事件攔截之後,那就要進行事件處理了,當然事件處理歸 onTouchEvent () 方法負責,onTouchEvent () 可以處理也可以不處理,如果 onTouchEvent () 返回 true 意味著事件處理完成,返回 false 則事件交由父 View 的 onTouchEvent () 方法進行處理,如圖示情況,MRelativeLayout 攔截了事件,但是沒有處理事件,最終交由 Activity 來處理咯。

事件處理#

onTouchEvent () 方法負責事件的處理,其返回值決定是否消費該事件,返回 true 表示當前 View 消費事件,返回 false 表示不消費事件,事件向複 View 的方向傳遞,按照上面的案例將 MRelativeLayout 的 onTouchEvent () 方法返回值設為 true,日誌截圖如下圖所示:

image

上面截圖中省略了若干 ACTION_MOVE 事件,當某一 View 事件攔截成功之後,ACTION_DOWN 之後的一系列事件將直接由該 View 處理。

總結#

  1. 事件分發由父 View 向子 View 進行事件的分發,在分發過程中如果沒有被攔截和處理,當分發至最深層次的 View 時,將向上回傳事件,最終交由 Activity 進行處理,後續事件也將不會接受;如果中途某個 View 攔截了事件並進行了處理,那麼由攔截事件的 View 的 onTouchEvent () 方法進行處理;如果中途某個 View 攔截了事件並且不進行處理,則事件停止向子 View 分發,然後向父 View 的方向交由父 View 的 onTouchEvent () 方法進行處理;
  2. 事件攔截成功之後則要對事件進行處理,事件的處理主要由攔截事件的 View 的 onTouchEvent () 方法或是其父 View 的 onTouchEvent () 來處理,是否處理具體由相應的 onTouchEvent () 方法的返回值決定;
  3. 事件的處理當然是 onTouchEvent () 方法了,返回 true 表示事件就此處理,反之事件未被處理,繼續向上回傳事件直至被處理。

相關文章#

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。