關(guān)于Android 事件分發(fā)機(jī)制,我根據(jù)畫的一張事件分發(fā)流程圖,說明的事件從用戶點(diǎn)擊之后端仰,在不同函數(shù)不同返回值的情況的最終走向捶惜。
注:
仔細(xì)看的話,圖分為3層荔烧,從上往下依次是Activity售躁、ViewGroup坞淮、View
事件從左上角那個(gè)白色箭頭開始,由Activity的dispatchTouchEvent做分發(fā)
箭頭的上面字代表方法返回值陪捷,(return true、return false诺擅、return super.xxxxx(),super 的意思是調(diào)用父類實(shí)現(xiàn)市袖。
dispatchTouchEvent和 onTouchEvent的框里有個(gè)【true---->消費(fèi)】的字,表示的意思是如果方法返回true烁涌,那么代表事件就此消費(fèi)苍碟,不會(huì)繼續(xù)往別的地方傳了,事件終止撮执。
目前所有的圖的事件是針對(duì)ACTION_DOWN的微峰,對(duì)于ACTION_MOVE和ACTION_UP我們最后做分析。
圖中的Activity 的dispatchTouchEvent 抒钱,只有return super.dispatchTouchEvent(ev) 才是往下走蜓肆,返回true 或者 false 事件就被消費(fèi)了(終止傳遞)。
1谋币、如果事件不被中斷仗扬,整個(gè)事件流向是一個(gè)類U型圖,我們來看下這張圖蕾额,可能更能理解U型圖的意思早芭。
所以如果我們沒有對(duì)控件里面的方法進(jìn)行重寫或更改返回值,而直接用super調(diào)用父類的默認(rèn)實(shí)現(xiàn)诅蝶,那么整個(gè)事件流向應(yīng)該是從Activity---->ViewGroup--->View 從上往下調(diào)用dispatchTouchEvent方法退个,一直到葉子節(jié)點(diǎn)(View)的時(shí)候,再由View--->ViewGroup--->Activity從下往上調(diào)用onTouchEvent方法调炬。
2语盈、dispatchTouchEvent 和 onTouchEvent 一旦return true,事件就停止傳遞了(到達(dá)終點(diǎn))(沒有誰能再收到這個(gè)事件)】鹁欤看下圖中只要return true事件就沒再繼續(xù)傳下去了黎烈,對(duì)于return true我們經(jīng)常說事件被消費(fèi)了,消費(fèi)了的意思就是事件走到這里就是終點(diǎn)匀谣,不會(huì)往下傳照棋,沒有誰能再收到這個(gè)事件了。
3武翎、dispatchTouchEvent 和 onTouchEvent return false的時(shí)候事件都回傳給父控件的onTouchEvent處理烈炭。
看上圖深藍(lán)色的線,對(duì)于返回false的情況宝恶,事件都是傳給父控件onTouchEvent處理符隙。
對(duì)于dispatchTouchEvent 返回 false 的含義應(yīng)該是:事件停止往子View傳遞和分發(fā)同時(shí)開始往父控件回溯(父控件的onTouchEvent開始從下往上回傳直到某個(gè)onTouchEvent return true)趴捅,事件分發(fā)機(jī)制就像遞歸,return false 的意義就是遞歸停止然后開始回溯霹疫。
對(duì)于onTouchEvent return false 就比較簡(jiǎn)單了拱绑,它就是不消費(fèi)事件,并讓事件繼續(xù)往父控件的方向從下往上流動(dòng)丽蝎。
4猎拨、dispatchTouchEvent、onTouchEvent屠阻、onInterceptTouchEvent
ViewGroup 和View的這些方法的默認(rèn)實(shí)現(xiàn)就是會(huì)讓整個(gè)事件安裝U型完整走完红省,所以 return super.xxxxxx() 就會(huì)讓事件依照U型的方向的完整走完整個(gè)事件流動(dòng)路徑),中間不做任何改動(dòng)国觉,不回溯吧恃、不終止,每個(gè)環(huán)節(jié)都走到麻诀。
所以如果看到方法return super.xxxxx() 那么事件的下一個(gè)流向就是走U型下一個(gè)目標(biāo)痕寓,稍微記住上面這張圖,你就能很快判斷出下一個(gè)走向是哪個(gè)控件的哪個(gè)函數(shù)针饥。
5厂抽、onInterceptTouchEvent 的作用
Intercept 的意思就攔截,每個(gè)ViewGroup每次在做分發(fā)的時(shí)候丁眼,問一問攔截器要不要攔截(也就是問問自己這個(gè)事件要不要自己來處理)如果要自己處理那就在onInterceptTouchEvent方法中 return true就會(huì)交給自己的onTouchEvent的處理筷凤,如果不攔截就是繼續(xù)往子控件往下傳。默認(rèn)是不會(huì)去攔截的苞七,因?yàn)樽覸iew也需要這個(gè)事件藐守,所以onInterceptTouchEvent攔截器return super.onInterceptTouchEvent()和return false是一樣的,是不會(huì)攔截的蹂风,事件會(huì)繼續(xù)往子View的dispatchTouchEvent傳遞卢厂。
6、ViewGroup 和View 的dispatchTouchEvent方法返回super.dispatchTouchEvent()的時(shí)候事件流走向惠啄。
首先看下ViewGroup 的dispatchTouchEvent慎恒,之前說的return true是終結(jié)傳遞。return false 是回溯到父View的onTouchEvent撵渡,然后ViewGroup怎樣通過dispatchTouchEvent方法能把事件分發(fā)到自己的onTouchEvent處理呢融柬,return true和false 都不行,那么只能通過Interceptor把事件攔截下來給自己的onTouchEvent趋距,所以ViewGroup dispatchTouchEvent方法的super默認(rèn)實(shí)現(xiàn)就是去調(diào)用onInterceptTouchEvent粒氧,記住這一點(diǎn)。
那么對(duì)于View的dispatchTouchEvent return super.dispatchTouchEvent()的時(shí)候呢事件會(huì)傳到哪里呢节腐,很遺憾View沒有攔截器外盯。但是同樣的道理return true是終結(jié)摘盆。return false 是回溯會(huì)父類的onTouchEvent碧信,怎樣把事件分發(fā)給自己的onTouchEvent 處理呢扔傅,那只能return super.dispatchTouchEvent,View類的dispatchTouchEvent()方法默認(rèn)實(shí)現(xiàn)就是能幫你調(diào)用View自己的onTouchEvent方法的缸榄。
說了這么多钠乏,不知道有說清楚沒有,我這邊最后總結(jié)一下:
對(duì)于 dispatchTouchEvent吵血,onTouchEvent尖殃,return true是終結(jié)事件傳遞以故。return false 是回溯到父View的onTouchEvent方法坦弟。
ViewGroup 想把自己分發(fā)給自己的onTouchEvent,需要攔截器onInterceptTouchEvent方法return true 把事件攔截下來官地。
ViewGroup 的攔截器onInterceptTouchEvent 默認(rèn)是不攔截的酿傍,所以return super.onInterceptTouchEvent()=return false;
View 沒有攔截器驱入,為了讓View可以把事件分發(fā)給自己的onTouchEvent赤炒,View的dispatchTouchEvent默認(rèn)實(shí)現(xiàn)(super)就是把事件分發(fā)給自己的onTouchEvent。
ViewGroup和View 的dispatchTouchEvent 是做事件分發(fā)亏较,那么這個(gè)事件可能分發(fā)出去的四個(gè)目標(biāo)
注:------> 后面代表事件目標(biāo)需要怎么做莺褒。
1、 自己消費(fèi)雪情,終結(jié)傳遞遵岩。------->return true ;
2巡通、 給自己的onTouchEvent處理-------> 調(diào)用super.dispatchTouchEvent()系統(tǒng)默認(rèn)會(huì)去調(diào)用 onInterceptTouchEvent尘执,在onInterceptTouchEvent return true就會(huì)去把事件分給自己的onTouchEvent處理。
3宴凉、 傳給子View------>調(diào)用super.dispatchTouchEvent()默認(rèn)實(shí)現(xiàn)會(huì)去調(diào)用 onInterceptTouchEvent 在onInterceptTouchEvent return false誊锭,就會(huì)把事件傳給子類。
4弥锄、 不傳給子View丧靡,事件終止往下傳遞,事件開始回溯籽暇,從父View的onTouchEvent開始事件從下到上回歸執(zhí)行每個(gè)控件的onTouchEvent------->return false温治;
注:由于View沒有子View所以不需要onInterceptTouchEvent 來控件是否把事件傳遞給子View還是攔截,所以View的事件分發(fā)調(diào)用super.dispatchTouchEvent()的時(shí)候默認(rèn)把事件傳給自己的onTouchEvent處理(相當(dāng)于攔截)图仓,對(duì)比ViewGroup的dispatchTouchEvent 事件分發(fā)罐盔,View的事件分發(fā)沒有上面提到的4個(gè)目標(biāo)的第3點(diǎn)。
ViewGroup和View的onTouchEvent方法是做事件處理的救崔,那么這個(gè)事件只能有兩個(gè)處理方式:
1惶看、自己消費(fèi)掉捏顺,事件終結(jié),不再傳給誰----->return true;
2纬黎、繼續(xù)從下往上傳幅骄,不消費(fèi)事件,讓父View也能收到到這個(gè)事件----->return false;View的默認(rèn)實(shí)現(xiàn)是不消費(fèi)的本今。所以super==false拆座。
ViewGroup的onInterceptTouchEvent方法對(duì)于事件有兩種情況:
1、攔截下來冠息,給自己的onTouchEvent處理--->return true;
2挪凑、不攔截,把事件往下傳給子View---->return false,ViewGroup默認(rèn)是不攔截的逛艰,所以super==false躏碳;
關(guān)于ACTION_MOVE 和 ACTION_UP
上面講解的都是針對(duì)ACTION_DOWN的事件傳遞,ACTION_MOVE和ACTION_UP在傳遞的過程中并不是和ACTION_DOWN 一樣散怖,你在執(zhí)行ACTION_DOWN的時(shí)候返回了false菇绵,后面一系列其它的action就不會(huì)再得到執(zhí)行了。簡(jiǎn)單的說镇眷,就是當(dāng)dispatchTouchEvent在進(jìn)行事件分發(fā)的時(shí)候咬最,只有前一個(gè)事件(如ACTION_DOWN)返回true,才會(huì)收到ACTION_MOVE和ACTION_UP的事件欠动。具體這句話很多博客都說了永乌,但是具體含義是什么呢?我們來看一下下面的具體分析翁垂。
上面提到過了铆遭,事件如果不被打斷的話是會(huì)不斷往下傳到葉子層(View),然后又不斷回傳到Activity沿猜,dispatchTouchEvent 和 onTouchEvent 可以通過return true 消費(fèi)事件枚荣,終結(jié)事件傳遞,而onInterceptTouchEvent 并不能消費(fèi)事件啼肩,它相當(dāng)于是一個(gè)分叉口起到分流導(dǎo)流的作用橄妆,ACTION_MOVE和ACTION_UP 會(huì)在哪些函數(shù)被調(diào)用,之前說了并不是哪個(gè)函數(shù)收到了ACTION_DOWN祈坠,就會(huì)收到 ACTION_MOVE 等后續(xù)的事件的害碾。
下面通過幾張圖看看不同場(chǎng)景下,ACTION_MOVE事件和ACTION_UP事件的具體走向并總結(jié)一下規(guī)律赦拘。
1慌随、我們?cè)赩iewGroup1 的dispatchTouchEvent 方法返回true消費(fèi)這次事件
ACTION_DOWN 事件從(Activity的dispatchTouchEvent)--------> (ViewGroup1 的dispatchTouchEvent) 后結(jié)束傳遞,事件被消費(fèi)(如下圖紅色的箭頭代碼ACTION_DOWN 事件的流向)。
//打印日志Activity |dispatchTouchEvent--> ACTION_DOWN ViewGroup1 |dispatchTouchEvent--> ACTION_DOWN---->消費(fèi)
在這種場(chǎng)景下ACTION_MOVE和ACTION_UP 將如何呢阁猜,看下面的打出來的日志
Activity | dispatchTouchEvent --> ACTION_MOVE
ViewGroup1 | dispatchTouchEvent --> ACTION_MOVE----
TouchEventActivity | dispatchTouchEvent --> ACTION_UP
ViewGroup1 | dispatchTouchEvent --> ACTION_UP
----
下圖中
紅色的箭頭代表ACTION_DOWN 事件的流向
藍(lán)色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向
2丸逸、我們?cè)赩iewGroup2 的dispatchTouchEvent 返回true消費(fèi)這次事件
Activity |dispatchTouchEvent--> ACTION_DOWN ViewGroup1 |dispatchTouchEvent--> ACTION_DOWNViewGroup1 |onInterceptTouchEvent--> ACTION_DOWNViewGroup2 |dispatchTouchEvent--> ACTION_DOWN---->消費(fèi)Activity |dispatchTouchEvent--> ACTION_MOVE ViewGroup1 |dispatchTouchEvent--> ACTION_MOVEViewGroup1 |onInterceptTouchEvent--> ACTION_MOVEViewGroup2 |dispatchTouchEvent--> ACTION_MOVE----TouchEventActivity |dispatchTouchEvent--> ACTION_UP ViewGroup1 |dispatchTouchEvent--> ACTION_UPViewGroup1 |onInterceptTouchEvent--> ACTION_UPViewGroup2 |dispatchTouchEvent--> ACTION_UP----
紅色的箭頭代表ACTION_DOWN 事件的流向
藍(lán)色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向
3、我們?cè)赩iew 的dispatchTouchEvent 返回true消費(fèi)這次事件
這個(gè)我不就畫圖了剃袍,效果和在ViewGroup2 的dispatchTouchEvent return true的差不多黄刚,同樣的收到ACTION_DOWN 的dispatchTouchEvent函數(shù)都能收到 ACTION_MOVE和ACTION_UP。
所以我們就基本可以得出結(jié)論如果在某個(gè)控件的dispatchTouchEvent 返回true消費(fèi)終結(jié)事件民效,那么收到ACTION_DOWN 的函數(shù)也能收到 ACTION_MOVE和ACTION_UP憔维。
4、我們?cè)赩iew 的onTouchEvent 返回true消費(fèi)這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍(lán)色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向
5畏邢、我們?cè)赩iewGroup 2 的onTouchEvent 返回true消費(fèi)這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍(lán)色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向
6业扒、我們?cè)赩iewGroup 1 的onTouchEvent 返回true消費(fèi)這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍(lán)色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向
7、我們?cè)贏ctivity 的onTouchEvent 返回true消費(fèi)這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍(lán)色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向
8舒萎、我們?cè)赩iew的dispatchTouchEvent 返回false并且Activity 的onTouchEvent 返回true消費(fèi)這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍(lán)色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向
9凶赁、我們?cè)赩iew的dispatchTouchEvent 返回false并且ViewGroup 1 的onTouchEvent 返回true消費(fèi)這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍(lán)色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向
10、我們?cè)赩iew的dispatchTouchEvent 返回false并且在ViewGroup 2 的onTouchEvent 返回true消費(fèi)這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍(lán)色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向
11逆甜、我們?cè)赩iewGroup2的dispatchTouchEvent 返回false并且在ViewGroup1 的onTouchEvent返回true消費(fèi)這次事件
紅色的箭頭代表ACTION_DOWN 事件的流向
藍(lán)色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向
12、我們?cè)赩iewGroup2的onInterceptTouchEvent 返回true攔截此次事件并且在ViewGroup 1 的onTouchEvent返回true消費(fèi)這次事件致板。
紅色的箭頭代表ACTION_DOWN 事件的流向
藍(lán)色的箭頭代表ACTION_MOVE 和 ACTION_UP 事件的流向
相信你也看出規(guī)律了交煞,對(duì)于在onTouchEvent消費(fèi)事件的情況:在哪個(gè)View的onTouchEvent 返回true,那么ACTION_MOVE和ACTION_UP的事件從上往下傳到這個(gè)View后就不再往下傳遞了斟或,而直接傳給自己的onTouchEvent 并結(jié)束本次事件傳遞過程素征。
對(duì)于ACTION_MOVE、ACTION_UP總結(jié):ACTION_DOWN事件在哪個(gè)控件消費(fèi)了(return true)萝挤, 那么ACTION_MOVE和ACTION_UP就會(huì)從上往下(通過dispatchTouchEvent)做事件分發(fā)往下傳御毅,就只會(huì)傳到這個(gè)控件,不會(huì)繼續(xù)往下傳怜珍,如果ACTION_DOWN事件是在dispatchTouchEvent消費(fèi)端蛆,那么事件到此為止停止傳遞,如果ACTION_DOWN事件是在onTouchEvent消費(fèi)的酥泛,那么會(huì)把ACTION_MOVE或ACTION_UP事件傳給該控件的onTouchEvent處理并結(jié)束傳遞今豆。