View的事件分發(fā)機(jī)制

一:點(diǎn)擊事件的分發(fā)過(guò)程由三個(gè)很重要的方法來(lái)共同完成:dispatchTouchEvent豫尽、onInterceptTouchEvent和onTouchEvent挪鹏。

上述三個(gè)方法到底有什么區(qū)別呢拉庶?它們是什么關(guān)系呢杨刨?其實(shí)它們的關(guān)系可以用如下偽代碼表示:

public boolean dispatchTouchEvent(MotionEvent ev) {

boolean consume =false;

? ? if (onInterceptTouchEvent(ev)) {

consume = onTouchEvent(ev);

? ? }else {

consume = child.dispatchTouchEvent(ev);

? ? }

return consume;

}

我們可以大致了解點(diǎn)擊事件的傳遞規(guī)則:對(duì)于一個(gè)根ViewGroup來(lái)說(shuō)映之,點(diǎn)擊事件產(chǎn)生后衰伯,首先會(huì)傳遞給它铡羡,這時(shí)它的dispatchTouchEvent就會(huì)被調(diào)用,如果這個(gè)ViewGroup的onInterceptTouchEvent返回true就表示它要攔截當(dāng)前事件意鲸,接著事件就會(huì)交給這個(gè)ViewGroup處理烦周,即它的onTouchEvent方法就會(huì)被調(diào)用;如果這個(gè)ViewGroup的onInterceptTouchEvent返回false就表示它不攔截當(dāng)前事件怎顾,這時(shí)當(dāng)前事件就會(huì)繼續(xù)傳遞給它的子元素读慎,接著子元素的dispatchTouchEvent方法就會(huì)被調(diào)用,如此反復(fù)直到事件最終處理槐雾。

當(dāng)一個(gè)View需要處理事件時(shí)夭委,如果它設(shè)置了OnTouchListener,那么OnTouchListener中的onTouch方法就會(huì)被調(diào)用。這時(shí)事件如何處理還要看onTouch的返回值募强,如果返回false株灸,則當(dāng)前View的onTouchEvent方法會(huì)被調(diào)用;如果返回true擎值,那么onTouchEvent方法將不會(huì)被調(diào)用慌烧。由此可見(jiàn),給View設(shè)置的OnTouchListener鸠儿,其優(yōu)先級(jí)比onTouchEvent要高屹蚊。在OnTouchEvent方法中,如果當(dāng)前設(shè)置的有OnClickListener进每,那么它的onClick方法會(huì)被調(diào)用汹粤。可以看出田晚,平時(shí)我們常用的onClickListener嘱兼,其優(yōu)先級(jí)最低,即處于事件傳遞的尾端贤徒。

當(dāng)一個(gè)點(diǎn)擊事件產(chǎn)生后芹壕,它的傳遞過(guò)程遵循如下順序:Activity->Window->View,即事件總是先傳遞給Activity胃惜,Activity再傳遞給Window,最后Window再傳遞給頂級(jí)View哪雕。頂級(jí)View接收到事件后,就會(huì)按照事件分發(fā)機(jī)制去分發(fā)事件鲫趁∷购浚考慮一種情況,如果一個(gè)View的onTouchEvent返回false挨厚,那么它的父容器的onTouchEvent將會(huì)被調(diào)用堡僻。以此類(lèi)推,如果所有的元素都不處理這個(gè)事件疫剃,那么這個(gè)事件將會(huì)最終傳遞給Activity處理钉疫,即Activity的onTouchEvent方法會(huì)被調(diào)用。關(guān)于事件傳遞的機(jī)制巢价,這里給出一些結(jié)論:

1.同一個(gè)事件序列是指從手指接觸屏幕的那一刻起牲阁,到手指離開(kāi)屏幕的那一刻結(jié)束,在這個(gè)過(guò)程中所產(chǎn)生的一系列事件壤躲,這個(gè)事件序列以down事件開(kāi)始城菊,中間含有數(shù)量不定的move事件,最終以u(píng)p事件結(jié)束碉克。

2.正常情況下凌唬,一個(gè)事件序列只能被一個(gè)View攔截且消耗。因?yàn)橐坏┮粋€(gè)元素?cái)r截了某此事件漏麦,那么同一個(gè)事件序列內(nèi)的所有事件都會(huì)直接交給它處理客税,因此同一個(gè)事件序列中的事件不能分別由兩個(gè)View同時(shí)處理,但是通過(guò)特殊手段可以做到撕贞,比如一個(gè)View將本該自己處理的事件通過(guò)onTouchEvent強(qiáng)行傳遞給其他的View處理更耻。

3.某個(gè)View一旦決定攔截,那么這一個(gè)事件序列都只能由它來(lái)處理(如果事件序列能夠傳遞給它的話(huà))麻掸,并且它的onInterceptTouchEvent不會(huì)再被調(diào)用酥夭。這條很好理解,就是說(shuō)當(dāng)一個(gè)View決定攔截一個(gè)事件后脊奋,那么系統(tǒng)會(huì)把同一個(gè)事件序列內(nèi)的其他方法都直接交給它來(lái)處理熬北,因此就不用在調(diào)用這個(gè)View的onInterceptTouchEvent去詢(xún)問(wèn)它是否要攔截了。

4.某個(gè)View一旦開(kāi)始處理事件诚隙,如果它不消耗ACTION_DOWN事件(onTouchEvent返回了false),那么同一事件序列中的其它事件都不會(huì)再交給它來(lái)處理讶隐,并且事件將重新交由它的父元素去處理,即父元素的onTouchEvent會(huì)被調(diào)用久又。意思就是事件一旦交給一個(gè)View處理巫延,那么它必須消耗掉效五,否則同一事件序列中剩下的事件就不再交給它來(lái)處理了,這就好比上級(jí)交給程序員一件事炉峰,如果這件事沒(méi)有處理好畏妖,短期內(nèi)上級(jí)就不敢再把事情交給這個(gè)程序員做了,二者是類(lèi)似的道理疼阔。

5.如果View不消除ACTION_DOWN以外的其它事件戒劫,那么這個(gè)點(diǎn)擊事件會(huì)消失,此時(shí)父元素的onTouchEvent并不會(huì)被調(diào)用婆廊,并且當(dāng)前View可以持續(xù)收到后續(xù)事件迅细,最終這些消失的點(diǎn)擊事件會(huì)傳遞給Activity處理。

6.ViewGroup默認(rèn)不攔截任何事件淘邻。Android源碼中的ViewGroup的onInterceptTouchEvent方法默認(rèn)返回false茵典。

7.View沒(méi)有onInterceptTouchEvent方法,一旦有點(diǎn)擠時(shí)間傳遞給它宾舅,那么它的onTouchEvent方法就會(huì)被調(diào)用统阿。

8.View的onTouchEvent默認(rèn)都會(huì)消耗事件(返回true),除非它是不可點(diǎn)擊的(clickable和longClickable同時(shí)為false)贴浙。View的longClickable屬性默認(rèn)都為false装黑,clickable屬性分情況嚎于,比如Button的clickable屬性默認(rèn)為true,而TextView的clickable屬性默認(rèn)為false。

9.View的enable屬性不影響onTouchEvent的默認(rèn)返回值幽污,哪怕一個(gè)View是disable狀態(tài)的忠售,只要它的clickable或者longClickable有一個(gè)為true刨沦,那么它的onTouchEvent就會(huì)返回true倍权。

10.onClick會(huì)發(fā)生的前提是當(dāng)前View是可點(diǎn)擊的,并且它收到了down和up的事件囱修。

11.事件傳遞過(guò)程是由外向內(nèi)的赎瑰,即事件總是先傳遞給父元素,然后再由父元素分發(fā)給子View破镰,通過(guò)requestDisallowInterceptTouchEvent方法可以在子元素中干預(yù)父元素的事件分發(fā)過(guò)程餐曼,但是Action_DOWN事件除外。

二鲜漩、

1.觸摸事件:Touch的事件主要是由一個(gè)ACION_DOWN,多個(gè)ACTION_MOVE源譬,一個(gè)ACTION_UP組成。三個(gè)方法:事件分發(fā)孕似、事件攔截踩娘、事件響應(yīng)。

2.事件分發(fā)(dispatchTouchEvent()):以隧道的形式從根元素向下傳遞喉祭,activity-layout-view

事件處理(onTouchEvent()):?從子元素一次往上傳遞view-layout-activity

? ?事件攔截?(

onInterceptTouchEvent())

事件分發(fā)圖解

事件分發(fā)(dispatchTouchEvent())在avtivity中的執(zhí)行情況

圖例

事件攔截(onInterceptTouchEvent()):

圖例

事件處理(onTouchEvent):

如果返回true养渴,則表示事件被消費(fèi)雷绢,不會(huì)往父控件傳遞

如果返回false和系統(tǒng)默認(rèn)值,則表示事件處理后沒(méi)有消費(fèi) 理卑,一樣會(huì)傳到父控件

?4.事件分發(fā):public?boolean?dispatchTouchEvent(MotionEvent?ev)

當(dāng)監(jiān)聽(tīng)到事件時(shí)翘紊,首先由activity的捕獲到,進(jìn)入事件分發(fā)流程藐唠。無(wú)論是activity還是View霞溪,如前文所說(shuō),事件分發(fā)自身也具有消費(fèi)能力中捆,如果事件返回true,表示該事件在本層不在進(jìn)行分發(fā)且已經(jīng)在事件分發(fā)自身中被消費(fèi)了坊饶。至此泄伪,事件已經(jīng)完結(jié)。如果你不想activity中的任何控件具有任何的事件消費(fèi)能力

最簡(jiǎn)單的方法就是重寫(xiě)此activity的dispatchTouchEvent方法匿级,直接返回true就OK蟋滴;

如果事件分發(fā)返回false,表明事件在本層中不在繼續(xù)進(jìn)行分發(fā)痘绎,并交由上層控件的onTouchEvent方法進(jìn)行消費(fèi)津函。

當(dāng)然了,如果本層控件已經(jīng)是Activity孤页,那么事件將會(huì)被系統(tǒng)消費(fèi)或處理尔苦。

?如果事件分發(fā)返回系統(tǒng)默認(rèn)的?super.dispatchTouchEvent(ev),事件將分發(fā)給本層的事件攔截onInterceptTouchEvent?方法進(jìn)行處理

(如果本層控件是Activity行施,由于其沒(méi)有事件攔截允坚,因此將直接將事件傳遞到子View,并交給子View的事件分發(fā)進(jìn)行處理)蛾号。

總結(jié):從以上過(guò)程中可以看出稠项,dispatchTouchEvent無(wú)論返回true還是false,事件都不再進(jìn)行分發(fā)鲜结,

只有當(dāng)其返回super.dispatchTouchEvent(ev)展运,才表明其具有向下層分發(fā)的愿望,

但是是否能夠分發(fā)成功精刷,則需要經(jīng)過(guò)事件攔截onInterceptTouchEvent的審核拗胜。事件是否具有冒泡特是由onTouchEvent的返回值決定的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末贬养,一起剝皮案震驚了整個(gè)濱河市挤土,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌误算,老刑警劉巖仰美,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件迷殿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡咖杂,警方通過(guò)查閱死者的電腦和手機(jī)庆寺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)诉字,“玉大人懦尝,你說(shuō)我怎么就攤上這事∪榔裕” “怎么了陵霉?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)伍绳。 經(jīng)常有香客問(wèn)我踊挠,道長(zhǎng),這世上最難降的妖魔是什么冲杀? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任效床,我火速辦了婚禮,結(jié)果婚禮上权谁,老公的妹妹穿的比我還像新娘剩檀。我一直安慰自己,他們只是感情好旺芽,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布沪猴。 她就那樣靜靜地躺著,像睡著了一般采章。 火紅的嫁衣襯著肌膚如雪字币。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天共缕,我揣著相機(jī)與錄音洗出,去河邊找鬼。 笑死图谷,一個(gè)胖子當(dāng)著我的面吹牛翩活,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播便贵,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼菠镇,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了承璃?” 一聲冷哼從身側(cè)響起利耍,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后隘梨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體程癌,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年轴猎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嵌莉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡捻脖,死狀恐怖锐峭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情可婶,我是刑警寧澤沿癞,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站矛渴,受9級(jí)特大地震影響抛寝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜曙旭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望晶府。 院中可真熱鬧桂躏,春花似錦、人聲如沸川陆。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)较沪。三九已至鳞绕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尸曼,已是汗流浹背们何。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留控轿,地道東北人冤竹。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像茬射,于是被迫代替她去往敵國(guó)和親鹦蠕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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