概述
相信很多寫過復(fù)雜自定義view的人都或多或少遇到一些事件響應(yīng)不對的坑始赎,在這里通過例子具象地把Android里事件分發(fā)消費(fèi)的機(jī)制解析清楚移必,一起來看吧移剪。
事件相關(guān)的主角
涉及到事件分發(fā)的類有Activity篙挽、ViewGroup赶掖、View
涉及到的函數(shù)有dispatchTouchEvent忿危、onInterceptTouchEvent达箍、onTouchEvent
Activity只有dispatchTouchEvent和onTouchEvent,沒有onInterceptTouchEvent
ViewGroup三個函數(shù)都有
View和Activity一樣沒有onInterceptTouchEvent
綜上所述铺厨,Activity和View都沒有onInterceptTouchEvent去攔截事件缎玫。
具體說明及測試?yán)?/h2>
先說說dispatchTouchEvent,當(dāng)事件產(chǎn)生時解滓,首先會進(jìn)入dispatch函數(shù)碘梢,由它決定事件是否繼續(xù)傳遞,它有三種返回值:
- true; 返回true表示事件只分發(fā)到這伐蒂,事件由本函數(shù)消費(fèi)煞躬。注意:事件不會分發(fā)到onTouchEvent中
- false; 返回false表示事件不往下分發(fā),也不消費(fèi),事件會逐層返回給父View進(jìn)行消費(fèi)
- super.dispatchTouchEvent; 系統(tǒng)默認(rèn)處理恩沛,如果有子view就分發(fā)給自己的子view在扰,如果自己是最小顆粒的view了,就直接調(diào)用onTouchEvent消費(fèi)
再來說說onInterceptTouchEvent雷客,如字面意思芒珠,就是攔截事件用的,也有三種返回值:
- true; 表示要攔截事件搅裙,事件由當(dāng)前view或viewgroup的onTouchEvent處理
- false; 表示不攔截事件皱卓,繼續(xù)往下分發(fā)
- super.onInterceptTouchEvent; 系統(tǒng)默認(rèn)處理,不攔截往下分發(fā)
最后說說onTouchEvent部逮,是消費(fèi)事件用的
- true; 消費(fèi)事件娜汁,事件結(jié)束
- false; 不消費(fèi),事件逐層返回給父View的onTouchEvent進(jìn)行消費(fèi)
- super.onTouchEvent; 系統(tǒng)默認(rèn)處理兄朋,同false
這樣說可能只知道方法的用處掐禁,具體傳遞還不明確,有點(diǎn)干颅和,現(xiàn)舉個例子說明吧:
name | dispatchTouchEvent | onInterceptTouchEvent | onTouchEvent |
---|---|---|---|
Activity | super | -- | super |
ViewGroup | super | super | super |
View | super | -- | super |
這是最常見的情況傅事,來看下點(diǎn)擊后事件傳遞的結(jié)果:
- Activity: dispatchTouchEvent---ACTION_DOWN
- ViewGroup: dispatchTouchEvent---ACTION_DOWN
- ViewGroup: onInterceptTouchEvent---ACTION_DOWN
- View: dispatchTouchEvent---ACTION_DOWN
- View: onTouchEvent---ACTION_DOWN
- ViewGroup: onTouchEvent---ACTION_DOWN
- Activity: onTouchEvent---ACTION_DOWN
- Activity: dispatchTouchEvent---ACTION_MOVE
- Activity: onTouchEvent---ACTION_MOVE
- Activity: dispatchTouchEvent---ACTION_UP
- Activity: onTouchEvent---ACTION_UP
因?yàn)閐ispatchTouchEvent全部是系統(tǒng)默認(rèn)處理,往下分發(fā)峡扩,得知路徑是自上而下蹭越,從根布局到子布局一層層傳遞,當(dāng)返回super時教届,如果有onInterceptTouchEvent方法(ViewGroup有)般又,就會先看下是否需要攔截事件,這里super,不攔截巍佑,分發(fā)給View茴迁,因?yàn)閂iew是最小顆粒度的控件了,沒有子view萤衰,所以直接觸發(fā)view的onTouchEvent去消費(fèi)堕义,這里返回super不消費(fèi),則依次返回給viewGroup的onTouchEvent消費(fèi)脆栋,這里viewGroup也不消費(fèi)倦卖,就返回給activity消費(fèi)。
這里看到當(dāng)找不到事件消費(fèi)者時椿争,后續(xù)事件的MOVE和UP都直接交給activity處理了怕膛,不會再分發(fā)∏刈伲可以理解成DOWN事件的分發(fā)就是為了尋找事件消費(fèi)者褐捻,找到了掸茅,后續(xù)的事件就直接交由消費(fèi)者去處理了。
name | dispatchTouchEvent | onInterceptTouchEvent | onTouchEvent |
---|---|---|---|
Activity | super | -- | super |
ViewGroup | true | super | super |
View | super | -- | super |
看結(jié)果:
- Activity: dispatchTouchEvent---ACTION_DOWN
- ViewGroup: dispatchTouchEvent---ACTION_DOWN
- Activity: dispatchTouchEvent---ACTION_MOVE
- ViewGroup: dispatchTouchEvent---ACTION_MOVE
- Activity: dispatchTouchEvent---ACTION_UP
- ViewGroup: dispatchTouchEvent---ACTION_UP
從結(jié)果可以發(fā)現(xiàn)柠逞,dispatchTouchEvent返回true時昧狮,直接消費(fèi)事件了,也不會經(jīng)過onInterceptTouchEvent和onTouchEvent板壮。
name | dispatchTouchEvent | onInterceptTouchEvent | onTouchEvent |
---|---|---|---|
Activity | super | -- | super |
ViewGroup | false | super | super |
View | super | -- | super |
看結(jié)果:
- Activity: dispatchTouchEvent---ACTION_DOWN
- ViewGroup: dispatchTouchEvent---ACTION_DOWN
- Activity: onTouchEvent---ACTION_DOWN
- Activity: dispatchTouchEvent---ACTION_MOVE
- Activity: onTouchEvent---ACTION_MOVE
- Activity: dispatchTouchEvent---ACTION_UP
- Activity: onTouchEvent---ACTION_UP
從結(jié)果可以發(fā)現(xiàn)逗鸣,dispatchTouchEvent返回false時,不往下分發(fā)事件绰精,事件直接返回上層去處理了撒璧,就到了Activity的onTouchEvent處理
name | dispatchTouchEvent | onInterceptTouchEvent | onTouchEvent |
---|---|---|---|
Activity | super | -- | super |
ViewGroup | super | true | super |
View | super | -- | super |
看結(jié)果:
- Activity: dispatchTouchEvent---ACTION_DOWN
- ViewGroup: dispatchTouchEvent---ACTION_DOWN
- ViewGroup: onInterceptTouchEvent---ACTION_DOWN
- ViewGroup: onTouchEvent---ACTION_DOWN
- Activity: onTouchEvent---ACTION_DOWN
- Activity: dispatchTouchEvent---ACTION_MOVE
- Activity: onTouchEvent---ACTION_MOVE
- Activity: dispatchTouchEvent---ACTION_UP
- Activity: onTouchEvent---ACTION_UP
從結(jié)果可以發(fā)現(xiàn),onInterceptTouchEvent返回true笨使,攔截了事件卿樱,把事件由攔截事件的ViewGroup進(jìn)行處理,所以走到了viewGroup的onTouchEvent阱表,因?yàn)関iewGroup沒有消費(fèi)事件殿如,所以事件直接返回上層去處理了贡珊,就到了Activity的onTouchEvent處理
name | dispatchTouchEvent | onInterceptTouchEvent | onTouchEvent |
---|---|---|---|
Activity | super | -- | super |
ViewGroup | super | true | true |
View | super | -- | super |
看結(jié)果:
- Activity: dispatchTouchEvent---ACTION_DOWN
- ViewGroup: dispatchTouchEvent---ACTION_DOWN
- ViewGroup: onInterceptTouchEvent---ACTION_DOWN
- ViewGroup: onTouchEvent---ACTION_DOWN
- Activity: dispatchTouchEvent---ACTION_MOVE
- ViewGroup: dispatchTouchEvent---ACTION_MOVE
- ViewGroup: onTouchEvent---ACTION_MOVE
- Activity: dispatchTouchEvent---ACTION_UP
- ViewGroup: dispatchTouchEvent---ACTION_MOVE
- ViewGroup: onTouchEvent---ACTION_UP
從結(jié)果可以發(fā)現(xiàn)最爬,ViewGroup的onTouchEvent返回true,消費(fèi)了事件后门岔,系統(tǒng)找到了可以消費(fèi)事件的view爱致,所以后續(xù)的MOVE\UP事件全部都分發(fā)到viewGroup里去消費(fèi)了
總結(jié)
由以上例子可以得出結(jié)論,DOWN事件的分發(fā)是為了找到可以消費(fèi)事件的目標(biāo)view寒随,找到后就會把后面的事件直接分發(fā)到此目標(biāo)view中糠悯。
分發(fā)是自上而下的,從根布局一直分發(fā)到子布局妻往,而消費(fèi)是自下而上的互艾,子view不消費(fèi)就會傳遞給父view去消費(fèi),只要有地方消費(fèi)了事件就中止傳遞讯泣。