Touch事件傳遞 個(gè)人分析

安卓的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
所以一切傳遞邏輯都是View.dispatchTouchEvent方法中控制的,在重載dispacthTouchEvent方法時(shí),super.dispatchTouchEvent的調(diào)用與否影響事件向下傳遞,dispatchTouchEvent的返回值影響事件的向上傳遞
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容