點(diǎn)擊事件的傳遞規(guī)則
當(dāng)一個(gè)MotionEvent產(chǎn)生之后座硕,系統(tǒng)需要把這個(gè)事件傳遞給一個(gè)具體的View,這個(gè)傳遞的過(guò)程就是分發(fā)過(guò)程涕蜂。
事件分發(fā)的三個(gè)重要方法
時(shí)間分發(fā)過(guò)程由三個(gè)方法共同完成:
-
public boolean dispatchTouchEvent(MotionEvent event)
- 用途:用來(lái)進(jìn)行事件分發(fā)华匾。
- 所屬:View的方法,ViewGroup中重寫(xiě)了這個(gè)方法机隙。
- 返回:當(dāng)前事件是否被消耗了蜘拉。
-
public boolean onInterceptTouchEvent(MotionEvent ev)
- 用途:判斷是否攔截某個(gè)事件刊头。
- 所屬:ViewGroup定義的方法。
- 調(diào)用:在ViewGroup的dispatchTouchEvent()中調(diào)用诸尽。
- 返回:是否攔截當(dāng)前事件。
-
public boolean onTouchEvent(MotionEvent event)
- 用途:用來(lái)處理點(diǎn)擊事件印颤。
- 所屬:View的方法您机,ViewGroup中沒(méi)有重寫(xiě)。
- 調(diào)用:在dispatchTouchEvent()中調(diào)用年局。
- 返回:是否消耗當(dāng)前事件际看。
ViewGroup中三個(gè)方法的大概關(guān)系如下圖(View沒(méi)有onInterceptTouchEvent(),默認(rèn)攔截):
這個(gè)圖只是大概梳理三個(gè)方法的關(guān)系矢否,其實(shí)是非常不完善的仲闽。
dispatchTouchEvent()去調(diào)用onTouchEvent()判斷當(dāng)前View是否攔截當(dāng)前事件,如果攔截就去調(diào)用onTouchEvent()處理事件僵朗,并返回其返回值赖欣,如果不攔截就調(diào)用子View的dispatchTouchEvent()(分發(fā)一直到存在一個(gè)View處理了事件),并返回其返回值验庙。
事件分發(fā)中的結(jié)論
這些結(jié)論都會(huì)在后面的源碼分析中體現(xiàn)出來(lái)顶吮,先留一個(gè)概念。
同一個(gè)事件序列是指手指接觸屏幕開(kāi)始到手指離開(kāi)屏幕過(guò)程中的產(chǎn)生的所有事件粪薛,以ACTION_DOWN開(kāi)始悴了,以ACTION_UP結(jié)束。后序事件就是指與當(dāng)前時(shí)間是同一事件序列的后面所有事件违寿。
分發(fā):
- 點(diǎn)擊事件產(chǎn)生之后湃交,事件的傳遞過(guò)程是Activity->Window->頂級(jí)View,再由父元素分發(fā)給子元素藤巢。
- requestDisallowInterceptTouchEvent()可以在子元素中干預(yù)父元素的事件分發(fā)搞莺,ACTION_DOWN除外。
攔截:
- View默認(rèn)攔截所有事件菌瘪,沒(méi)有onIntercepTouchEvent()腮敌。
- ViewGroup默認(rèn)不攔截任何事件,onIntercepTouchEvent()默認(rèn)返回false俏扩。
- 正常情況下糜工,一個(gè)事件序列只能被一個(gè)View攔截并消耗,通過(guò)onTouchEvent()強(qiáng)行傳遞給其他的View可以做到录淡。
- 當(dāng)一個(gè)View決定攔截一個(gè)事件后捌木,同事件序列中的后序事件都會(huì)交給它處理。后序事件不再調(diào)onIntercepTouchEvent()嫉戚,會(huì)默認(rèn)攔截刨裆。
- 如果一個(gè)View不消耗ACTION_DOWN(onTouchEvent()返回false)澈圈,后序事件都不再交給它處理。不再調(diào)用onIntercepTouchEvent()帆啃,直接不攔截瞬女。
- 如果一個(gè)View攔截并消耗了ACTION_DOWN,但是沒(méi)有消耗后序事件努潘,此時(shí)父View的onTouchEvent()不會(huì)被調(diào)用诽偷,當(dāng)前View可以持續(xù)收到后序事件,最后這些事件會(huì)傳遞給Activity處理疯坤。
消耗:
- View的onTouchEvent()默認(rèn)攔截事件报慕,除非View是不可點(diǎn)擊的(clickable和longClickable都為fale),不受enable的影響压怠。
- 當(dāng)View需要消耗一個(gè)事件時(shí)眠冈,如果設(shè)置了OnTouchListener,那么onTouch()就會(huì)被調(diào)用菌瘫,并且只有當(dāng)onTouch()返回false的時(shí)候onTouchEvent()才會(huì)被調(diào)用蜗顽。所以可見(jiàn),OnTouchListener優(yōu)先級(jí)比onTouchEvent高突梦。
- 如果設(shè)置了OnClickListener诫舅,那么在onTouchEvent()中會(huì)調(diào)用onClick()。所以可見(jiàn)OnClickListener優(yōu)先級(jí)比較低宫患。