【Android基礎】講講Android的事件分發機制
Android的事件分發機制涉及的知識點很多,為了方便記憶和知識總結,小編決定專門開一篇文章,記錄相關知識。
話不多說,我們直入主題。
##面試場景
今天找到了幾個自己之前校招時記錄的關於事件分發
的幾個面試題。
講講Android的事件分發機制
基本會遵從Activity => ViewGroup => View的順序進行事件分發,然後通過呼叫onTouchEvent()
方法進行事件的處理。我們在專案中一般會對
MotionEvent.ACTION_DOWN
,MotionEvent.ACTION_UP
, MotionEvent.ACTION_MOVE
分情況進行操作。
有去檢視原始碼中的事件攔截方法嗎?瞭解過相關原始碼嗎?
事件攔截分為內部攔截法
和外部攔截法
,對於外部攔截法,我們可以重寫ViewGroup的onInterceptEvent()
;對於內部攔截法,我們可以通過
requestDisallowInterceptTouchEvent()
來控制父容器是否攔截。
在一個列表中,同時對父View和子View設定點選事件,優先響應哪個?為什麼會這樣?
優先響應子View,因為當父View決定不攔截子View後,就會調dispatchTouchEvent
,ViewGroup的這個方法會先去遍歷呼叫子View的dispatchTouchEvent
,如果都返回false,才會走到父View的onTouchEvent
。
這三個問題只是簡單的熱身,要想了解Android的事件分發機制,還是得熟讀原始碼。關於事件分發
,應該分Activity、ViewGroup、View這三種情況來講。
而且,說到事件分發,有三個非常重要的方法也不得不提。
- dispatchTouchEvent()
- onTouchEvent()
- onInterceptTouchEvent()
##Activity的事件分發機制
顧名思義,dispatchTouchEvent()
是負責事件分發的。當點選事件產生後,事件會傳遞給當前Activity,這時會呼叫Activity的dispatchTouchEvent()
,我們來看原始碼。
在上面這段程式碼中,我們來看下getWindow().superDispatchTouchEvent()
,getWindow()
明顯是獲取Window
,這個就是我們很熟的PhoneWindow
了。我們直接看看PhoneWindow
的superDispatchTouchEvent()
到底做了什麼操作。
直接呼叫了DecorView
的superDispatchTouchEvent()
方法。DecorView
繼承於FrameLayout
,作為頂層View,是所有介面的父類。而FrameLayout
作為ViewGroup
的子類,所以直接呼叫了ViewGroup
的dispatchTouchEvent()
。
##ViewGroup的事件分發機制
我們通過檢視ViewGroup
的dispatchTouchEvent()
可以發現。
我們分段來看dispatchTouchEvent()。
注:本文中原始碼都經過了小編刪減,只展示與事件分發相關邏輯。
我們來看如上程式碼中的紅框部分:ACTION_DOWN
事件一定會交由ViewGroup處理,子View沒辦法攔截,因為resetTouchState()
會把requestDisallowInterceptTouchEvent()
所置的標誌位重置
。
我們再來看紅框外的部分:首先定義了一個變數intercept
來表示是否攔截事件。
其中採用了onInterceptTouchEvent()
對intercept
進行賦值。大多數情況下,onInterceptTouchEvent()
返回值為false,但我們可以重寫onInterceptTouchEvent()
來改變它的返回值,我們往下看後面這個intercept
是如何被用到的。
可以看到,當intercept
是false時,會通過for
迴圈去遍歷ViewGroup
的child
,然後呼叫dispatchTransformedTouchEvent()
,如果dispatchTransformedTouchEvent()
返回值是true,就去呼叫addTouchTarget()
。
而當intercept
是true時,就不會去遍歷ViewGroup
的child
,也更不會呼叫child的
dispatchTransformedTouchEvent()
了。
這裡我們還需要看下dispatchTransformedTouchEvent()
和addTouchTarget()
的原始碼是如何實現的。
在for
迴圈裡,傳入給dispatchTransformedTouchEvent()
的child
不為null
,所以呼叫的是子View的dispatchTouchEvent()
。
如果子View的dispatchTouchEvent()
返回true,則呼叫addTouchTarget()
。
這個方法裡,我們只需要注意一點:給mFirstTouchTarget
賦值。
我們來整理一下思路:
當事件傳遞給ViewGroup,先去遍歷呼叫child的dispatchTouchEvent()
,如果有child的dispatchTouchEvent()
返回了true
,mFirstTouchTarget
就被賦值,否則mFirstTouchTarget
就為null
。
至此,dispatchTouchEvent()就快看完了,我們來看下mFirstTouchTarget
是如何被使用到的。
如上,如果mFirstTouchTarget
為null
,就去呼叫super.dispatchTouchEvent()
。
我們知道ViewGroup
的super
是View
,所以,當ViewGroup
的所有child的dispatchTouchEvent()
都返回false,就呼叫父容器的dispatchTouchEvent()
。
總結一下,ViewGroup的事件傳遞過程可以通過如下虛擬碼表示:
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean consume = false;
if (onInterceptTouchEvent(ev)) {
consume = onTouchEvent(ev);
} else {
consume = child.dispatchTouchEvent(ev);
}
return consume;
}
##View的事件分發機制
上節我們講到,當ViewGroup
的所有child都沒有消費事件,就呼叫super.dispatchTouchEvent()
,而ViewGroup
的super
是View
,所以我們來看下View
的dispatchTouchEvent()
。
View
的dispatchTouchEvent()
已經說的很清楚了:onTouchListener
的優先順序大於onTouchEvent
。如果onTouchListener
返回true
了,就不呼叫onTouchEvent
了。
我們下面再看看onTouchEvent()
的原始碼。
在手指抬起的時候都會呼叫performClick
。如果設定了onClickListener
,就會呼叫onClickListener.onClick
。
##總結
1、Android事件分發總是遵循Activity => ViewGroup => View的傳遞順序
2、onTouchListener的優先順序大於onTouchEvent。
##參考
https://blog.csdn.net/jiangwei0910410003/article/details/17504315
https://www.cnblogs.com/qlky/p/6675882.html
https://blog.csdn.net/jaysong2012/article/details/45535521
https://www.jianshu.com/p/d3758eef1f72
相關文章
- 面試:講講 Android 的事件分發機制面試Android事件
- 講講Android事件攔截機制Android事件
- Android事件分發機制:基礎篇:最全面、最易懂Android事件
- Android事件分發機制Android事件
- Android Touch事件傳遞機制通俗講解Android事件
- Android的MotionEvent事件分發機制Android事件
- Android 事件分發機制的理解Android事件
- Android事件分發機制探究Android事件
- Android事件分發機制解析Android事件
- Android View 的事件體系 -- 事件分發機制AndroidView事件
- android事件分發機制詳解Android事件
- 完全理解android事件分發機制Android事件
- 圖解 Android 事件分發機制圖解Android事件
- Android ViewGroup事件分發機制AndroidView事件
- 可能是講解 Android 事件分發最好的文章Android事件
- Android事件分發機制三:事件分發工作流程Android事件
- 基於原始碼分析 Android View 事件分發機制原始碼AndroidView事件
- 淺談Android中的事件分發機制Android事件
- 【Android原始碼】View的事件分發機制Android原始碼View事件
- Android事件分發機制簡單理解Android事件
- Android 事件分發機制原始碼解析Android事件原始碼
- 淺談Android 事件分發機制(二)Android事件
- 深入淺出Android事件分發機制:最全面最易懂:基礎篇(一)Android事件
- 10分鐘理解 Android View 事件分發機制AndroidView事件
- Android事件分發:從原始碼角度分析View事件分發機制Android事件原始碼View
- Android ViewGroup 事件分發機制詳解AndroidView事件
- 最全面的Android Intent機制講解AndroidIntent
- 《Android開發藝術探索》——View事件分發機制AndroidView事件
- Android事件分發機制,你瞭解過嗎?Android事件
- Android 事件分發機制原始碼解析-view層Android事件原始碼View
- android觸控事件分發機制,曾困惑你我的地方Android事件
- 這可能是最"俗"的View的事件分發機制(含Demo講解)View事件
- Android事件分發機制五:面試官你坐啊Android事件面試
- Android自定義View之事件分發機制總結AndroidView事件
- Android 事件分發機制原始碼詳解-最新 APIAndroid事件原始碼API
- Android從原始碼角度剖析View事件分發機制Android原始碼View事件
- Android事件分發機制之原始碼完美解析(上)Android事件原始碼
- Android事件分發機制、滑動衝突解決Android事件