Android事件分發(fā)消費(fèi)機(jī)制(一)

一婴洼、簡(jiǎn)介 :

????????Activity或View類的onTouchEvent()回調(diào)函數(shù)會(huì)接收到touch事件⊥沂欤  
一個(gè)完整的手勢(shì)是從ACTION_DOWN開始摘投,到ACTION_UP結(jié)束。
簡(jiǎn)單的情況下懂傀,我們只需要在onTouchEvent()中寫個(gè)switch case語(yǔ)句趾诗,處理各種事件(Touch Down、 Touch Move蹬蚁、 Touch Up等)恃泪,但是比較復(fù)雜的動(dòng)作就需要更多的處理了。
  
????????ViewGroup作為一個(gè)parent是可以截獲傳向它的child的touch事件的缚忧。如果一個(gè)ViewGroup的onInterceptTouchEvent()方法返回true悟泵,說(shuō)明Touch事件被截獲,子View不再接收到Touch事件闪水,而是轉(zhuǎn)向本ViewGroup的 onTouchEvent()方法處理糕非。從Down開始,之后的Move球榆,Up都會(huì)直接在onTouchEvent()方法中處理朽肥。
先前還在處理touch event的child view將會(huì)接收到一個(gè) ACTION_CANCEL。如果onInterceptTouchEvent()返回false持钉,則事件會(huì)交給child view處理衡招。
  
????????Android中提供了ViewGroup、View每强、Activity三個(gè)層次的Touch事件處理始腾。處理過(guò)程是按照Touch事件從上到下傳遞州刽,再按照是否消費(fèi)的返回值,從下到上返回浪箭,即如果View的onTouchEvent返回false穗椅,將會(huì)向上傳給它的parent的ViewGroup,如果ViewGroup不處理奶栖,將會(huì)一直向上返回到Activity匹表。即隧道式向下分發(fā),然后冒泡式向上處理宣鄙。

二袍镀、3個(gè)重要的方法的講解

1、 Android 中與 Touch 事件相關(guān)的方法包括:dispatchTouchEvent(MotionEvent ev)冻晤、onInterceptTouchEvent(MotionEvent ev)苇羡、onTouchEvent(MotionEvent ev);能夠響應(yīng)這些方法的控件包括:ViewGroup明也、View宣虾、Activity。方法與控件的對(duì)應(yīng)關(guān)系如下表所示:

Touch 事件相關(guān)方法 方法功能 View ViewGroup Activity
public boolean dispatchTouchEvent(MotionEvent ev) 事件分發(fā) Yes Yes Yes
public boolean onInterceptTouchEvent(MotionEvent ev) 事件攔截 Yes Yes / No No
public boolean onTouchEvent(MotionEvent ev) 事件響應(yīng) Yes Yes Yes

2温数、小結(jié)
從這張表中我們可以看到 ViewGroup 和 View 對(duì)與 Touch 事件相關(guān)的三個(gè)方法均能響應(yīng)绣硝,而 Activity 對(duì)onInterceptTouchEvent(MotionEvent ev) 也就是事件攔截不進(jìn)行響應(yīng)。另外需要注意的是 View 對(duì) onInterceptTouchEvent(MotionEvent ev) 的響應(yīng)的前提是可以向該 View 中添加子 View撑刺,如果當(dāng)前的 View 已經(jīng)是一個(gè)最小的單元 View(比如 TextView)鹉胖,那么就無(wú)法向這個(gè)最小 View 中添加子 View,也就無(wú)法向子 View 進(jìn)行事件的攔截够傍,所以它沒有 onInterceptTouchEvent(MotionEvent ev)甫菠。

事件分發(fā)消費(fèi)機(jī)制.jpg

3、三個(gè)方法的用法:

1冕屯、)dispatchTouchEvent() 用來(lái)分派事件寂诱。
其中調(diào)用了onInterceptTouchEvent()和onTouchEvent(),一般不重寫該方法

2安聘、)onInterceptTouchEvent() 用來(lái)攔截事件痰洒。
ViewGroup類中的源碼實(shí)現(xiàn)就是{return false;}表示不攔截該事件,
事件將向下傳遞(傳遞給其子View)浴韭;
若手動(dòng)重寫該方法丘喻,使其返回true則表示攔截,事件將終止向下傳遞念颈,
事件由當(dāng)前ViewGroup類來(lái)處理泉粉,就是調(diào)用該類的onTouchEvent()方法

3、)onTouchEvent() 用來(lái)處理事件。
返回true則表示該View能處理該事件嗡靡,事件將終止向上傳遞(傳遞給其父View)跺撼;返回false表示不能處理,則把事件傳遞給其父View的onTouchEvent()方法來(lái)處理

【注】:ViewGroup的某些子類(GridView叽躯、ScrollView...)重寫了onInterceptTouchEvent()方法财边,當(dāng)發(fā)生ACTION_MOVE事件時(shí),返回true進(jìn)行攔截点骑。

四、Touch 事件分析
(一)谍夭、事件分發(fā):public boolean dispatchTouchEvent(MotionEvent ev)
Touch 事件發(fā)生時(shí) Activity 的 dispatchTouchEvent(MotionEvent ev) 方法會(huì)以隧道方式(從根元素依次往下傳遞直到最內(nèi)層子元素或在中間某一元素中由于某一條件停止傳遞)將事件傳遞給最外層 View 的 dispatchTouchEvent(MotionEvent ev) 方法黑滴,并由該 View 的 dispatchTouchEvent(MotionEvent ev) 方法對(duì)事件進(jìn)行分發(fā)。

(二)紧索、事件攔截:public boolean onInterceptTouchEvent(MotionEvent ev)
在外層 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系統(tǒng)默認(rèn)的 super.dispatchTouchEvent(ev) 情況下袁辈,事件會(huì)自動(dòng)的分發(fā)給當(dāng)前 View 的 onInterceptTouchEvent 方法。onInterceptTouchEvent 的事件攔截邏輯如下:
?如果 onInterceptTouchEvent 返回 true珠漂,則表示將事件進(jìn)行攔截晚缩,并將攔截到的事件交由當(dāng)前 View 的 onTouchEvent 進(jìn)行處理;
?如果 onInterceptTouchEvent 返回 false媳危,則表示將事件放行荞彼,當(dāng)前 View 上的事件會(huì)被傳遞到子 View 上,再由子 View 的 dispatchTouchEvent 來(lái)開始這個(gè)事件的分發(fā)待笑;
?如果 onInterceptTouchEvent 返回 super.onInterceptTouchEvent(ev)鸣皂,事件默認(rèn)不會(huì)被攔截,并將攔截到的事件交由當(dāng)前 View 的 onTouchEvent 進(jìn)行處理暮蹂。

(三)寞缝、事件響應(yīng):public boolean onTouchEvent(MotionEvent ev)
在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true 或返回 super.onInterceptTouchEvent(ev) 的情況下 onTouchEvent 會(huì)被調(diào)用。onTouchEvent 的事件響應(yīng)邏輯如下:
?如果事件傳遞到當(dāng)前 View 的 onTouchEvent 方法仰泻,而該方法返回了 false荆陆,那么這個(gè)事件會(huì)從當(dāng)前 View 向上傳遞,并且都是由上層 View 的 onTouchEvent 來(lái)接收集侯,如果傳遞到上面的 onTouchEvent 也返回 false被啼,這個(gè)事件就會(huì)“消失”,而且接收不到下一次事件浅悉。
?如果返回了 true 則會(huì)接收并消費(fèi)該事件趟据。
?如果返回 super.onTouchEvent(ev) 默認(rèn)處理事件的邏輯和返回 false 時(shí)相同。

onInterceptTouchEvent用于改變事件的傳遞方向术健。決定傳遞方向的是返回值汹碱,返回為false時(shí)事件會(huì)傳遞給子控件,返回值為true時(shí)事件會(huì)傳遞給當(dāng)前控件的onTouchEvent()荞估,這就是所謂的Intercept(攔截)咳促。ii
正確的使用方法是稚新,在此方法內(nèi)僅判斷事件是否需要攔截,然后返回跪腹。即便需要攔截也應(yīng)該直接返回true褂删,然后由onTouchEvent方法進(jìn)行處理。
onTouchEvent用于處理事件冲茸,返回值決定當(dāng)前控件是否消費(fèi)(consume)了這個(gè)事件屯阀。尤其對(duì)于ACTION_DOWN事件,返回true轴术,表示我想要處理后續(xù)事件难衰;返回false,表示不關(guān)心此事件逗栽,并返回由父類進(jìn)行處理盖袭。
可能你要問(wèn)是否消費(fèi)了又區(qū)別嗎,反正我已經(jīng)針對(duì)事件編寫了處理代碼彼宠?答案是有區(qū)別鳄虱!比如ACTION_MOVE或者ACTION_UP發(fā)生的前提是一定曾經(jīng)發(fā)生了ACTION_DOWN,如果你沒有消費(fèi)ACTION_DOWN凭峡,那么系統(tǒng)會(huì)認(rèn)為ACTION_DOWN沒有發(fā)生過(guò)拙已,所以ACTION_MOVE或者ACTION_UP就不能被捕獲。
在沒有重寫onInterceptTouchEvent()和onTouchEvent()的情況下(他們的返回值都是false)
Android系統(tǒng)中的每個(gè)View的子類都具有下面三個(gè)和TouchEvent處理密切相關(guān)的方法:
1)public boolean dispatchTouchEvent(MotionEvent ev) 這個(gè)方法用來(lái)分發(fā)TouchEvent
2)public boolean onInterceptTouchEvent(MotionEvent ev) 這個(gè)方法用來(lái)攔截TouchEvent
3)public boolean onTouchEvent(MotionEvent ev) 這個(gè)方法用來(lái)處理TouchEvent

1想罕、如果dispatchTouchEvent返回true 悠栓,則交給這個(gè)view的onTouchEvent處理, 如果最終需要處理事件的view的onTouchEvent()返回了false按价,那么該事件將被傳遞至其上一層次的view的onTouchEvent()處理惭适。如果最終需要處理事件的view 的onTouchEvent()返回了true,那么后續(xù)事件將可以繼續(xù)傳遞給該view的onTouchEvent()處理楼镐。
2癞志、如果dispatchTouchEvent返回 false ,則交給這個(gè) view的interceptTouchEvent方法來(lái)決定是否
要攔截這個(gè)事件框产,如果 interceptTouchEvent 返回 true 凄杯,表示攔截掉了,則交給它的 onTouchEvent 來(lái)處理秉宿,如果 interceptTouchEvent 返回 false 戒突,那么就傳遞給子view ,由子 view 的 dispatchTouchEvent 再來(lái)開始這個(gè)事件的分發(fā)描睦。
3膊存、如果事件傳遞到某一層的子 view 的onTouchEvent 上了,這個(gè)方法返回了 false ,那么這個(gè)事件
會(huì)從這個(gè)view 往上傳遞隔崎,都是 onTouchEvent 來(lái)接收今艺。如果傳遞到最上面的 onTouchEvent 也返回 false 的話,這個(gè)事件就會(huì)“消失”爵卒,而且接收不到下一次事件虚缎。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市钓株,隨后出現(xiàn)的幾起案子实牡,更是在濱河造成了極大的恐慌,老刑警劉巖轴合,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铲掐,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡值桩,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門豪椿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)奔坟,“玉大人,你說(shuō)我怎么就攤上這事搭盾】缺” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵鸯隅,是天一觀的道長(zhǎng)澜建。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蝌以,這世上最難降的妖魔是什么炕舵? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮跟畅,結(jié)果婚禮上咽筋,老公的妹妹穿的比我還像新娘。我一直安慰自己徊件,他們只是感情好奸攻,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著虱痕,像睡著了一般睹耐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上部翘,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天硝训,我揣著相機(jī)與錄音,去河邊找鬼。 笑死捎迫,一個(gè)胖子當(dāng)著我的面吹牛晃酒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播窄绒,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼贝次,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了彰导?” 一聲冷哼從身側(cè)響起蛔翅,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎位谋,沒想到半個(gè)月后山析,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掏父,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年笋轨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赊淑。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡爵政,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出陶缺,到底是詐尸還是另有隱情钾挟,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布饱岸,位于F島的核電站掺出,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏苫费。R本人自食惡果不足惜汤锨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望黍衙。 院中可真熱鬧泥畅,春花似錦、人聲如沸琅翻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)方椎。三九已至聂抢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間棠众,已是汗流浹背琳疏。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工有决, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人空盼。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓书幕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親揽趾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子台汇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容