安卓的Touch事件傳遞處理主要與三個(gè)方法有關(guān),分別為
- 傳遞——dispatchTouchEvent()函數(shù)、
- 攔截——onInterceptTouchEvent()函數(shù)、
- 消費(fèi)——onTouchEvent()函數(shù)
其調(diào)用順序與上述一致,其中onInterceptTouchEvent函數(shù)只有ViewGroup才有
借用網(wǎng)上的兩張圖片

clipboard.png

clipboard.png
主要內(nèi)容就是:
1.事件通過dispatch函數(shù)向下傳遞,通過onTouch函數(shù)向上冒泡
2.當(dāng)onTouch函數(shù)返回true時(shí),表示事件被消費(fèi),從而使事件不再向上冒泡
3.當(dāng)onInterceptTouchEvent函數(shù)返回true時(shí),表示阻止事件的向下傳遞,如果當(dāng)前view不消費(fèi)事件,則事件會(huì)從當(dāng)前層次在onTouch向上冒泡
4.當(dāng)某一層View 的action_down事件不消費(fèi)時(shí),該view就不會(huì)收到后續(xù)的move和up事件
網(wǎng)上資料都說,onTouch返回true表示消費(fèi)事件,onInterceptTouchEvent返回true表示攔截事件,onDispatchEvent返回true又表示什么?這三個(gè)返回值相互之間有什么制約呢?當(dāng)我重載他們并通過打log發(fā)現(xiàn),log信息并不是我想象中的那樣
實(shí)驗(yàn)前:
- 所有的層的dispatchTouchEvent都直接調(diào)用父類的方法 return super.dispatchTouchEvent( ),后面的測試在不說明的情況下這是默認(rèn)的做法
- 除非特別說明,否則所有的onInterceptTouchEvent方法都緊跟著dispatch方法后被調(diào)用,圖里不再標(biāo)示
- “調(diào)用super,但直接返回false” ,意思是在代碼中
super.xxxxEvent();
return false;
而不是return super.xxxEvent();
例一

clipboard.png
討論分析
- ViewGroup的interceptTouchEvent緊跟著dispatchTouchEvent之后調(diào)用, intercept和ontouch默認(rèn)情況下返回false;
- View和viewgroup在不消費(fèi)action_down事件的情況下,不會(huì)觸發(fā)后續(xù)的action_move、action_up等事件
- activity即使不消費(fèi)action_down事件,依然會(huì)在兩個(gè)方法中收到move和up事件
例二(也是比較常見的情況)

clipboard.png
討論分析
- View在onTouch消費(fèi)了所有事件,所以只有View的onTouch方法被調(diào)用,事件不向上傳遞。情況簡單,不多述
例三(開始不太正常)

clipboard.png
討論分析
- ViewGroup2之上的所有的intercep方法會(huì)被調(diào)用(這個(gè)例子中是指viewgroup的intercept,同樣是跟在dispatch之后),但ViewGroup2的Intercep方法不會(huì)調(diào)用
- 所有的onTouch方法不會(huì)被調(diào)用
例4

clipboard.png
討論分析
當(dāng)我們不在dispatch方法中調(diào)用super且直接返回false時(shí),事件傳遞邏輯就變得有點(diǎn)亂
- ViewGroup2的onTouch不被調(diào)用,但onTouch事件能從上一層開始正常冒泡
- 由于action_down不消費(fèi),則后續(xù)事件不再傳下來
總結(jié)
- activity的onTouch和dispatch方法無論任何事件、事件是否被消費(fèi)都會(huì)被調(diào)用
- 這三個(gè)方法的調(diào)用并不是我們想像中的獨(dú)立的線性關(guān)系,而是調(diào)用與被調(diào)用的關(guān)系,onTouch和onIntercept方法其實(shí)是在view的dispathTouchEvent方法中被調(diào)用的,而且dispathTouchEvent的返回值參考了onTouch的返回值,如果我們重載dipatch時(shí)不調(diào)用super.dispatch,則這個(gè)view的onTouch、onIntercept方法不會(huì)被調(diào)用
- super.dispathTouchEvent的返回值與onTouch的返回一致,onTouch返回true之所以能阻止事件向上傳遞是因?yàn)槠涫沟胐ispathTouchEvent也返回了true。這時(shí)如果你重載dispathTouchEvent強(qiáng)制返回false,依然無法阻止事件向上冒泡
- 要使事件向下傳遞,必需在dispatch中調(diào)用super.dispatch(如果你重載它的話),如果不調(diào)用super,就代表截?cái)r事件,但不代表消費(fèi)事件,因?yàn)檫@時(shí)onTouch不會(huì)被調(diào)用,無法消費(fèi),但事件會(huì)從上一層開始在onTouch中向上冒泡,如 例4