Android事件機(jī)制(二)

關(guān)于Android事件機(jī)制亏镰,很多大神都做了分析嬉探,我也是通過他們的帖子進(jìn)行學(xué)習(xí)臼寄,在此特向他們表達(dá)謝意伪朽。
Android事件機(jī)制(一)從代碼演示的角度整理了一下我對Android事件傳遞的理解,下面就通過源碼淺顯的分析一下個(gè)人理解(想想源碼铭乾,就覺任重而道遠(yuǎn)剪廉,笑cry)。

那么來看一下上篇中提到的炕檩,“有觸摸斗蒋,就有dispatchTouchEvent方法的調(diào)用”,這個(gè)dispatchTouchEvent方法笛质。
雖然dispatchTouchEvent方法是事件分發(fā)的第一步泉沾,但是一般情況下不太會(huì)去改寫這個(gè)方法,只是onInterceptTouchEvent妇押、onTouchEvent跷究、OnTouchListener.onTouch這幾個(gè)方法都會(huì)被其以不同的條件調(diào)用,這也就決定了事件如何傳遞敲霍。

點(diǎn)擊MyView俊马,首先會(huì)調(diào)用到MyView最高父輩的dispatchTouchEvent方法,這里從MyViewGroupA.dispatchTouchEvent開始色冀,而MyViewGroupA繼承自RelativeLayout潭袱,因此我們進(jìn)入到了ViewGroup.dispatchTouchEvent

當(dāng)事件到來的時(shí)候锋恬,ViewGroup.dispatchTouchEvent會(huì)先判斷是否要攔截事件:

ViewGroup.dispatchTouchEvent

從2094行可以看出屯换,事件機(jī)制從MotionEvent.ACTION_DOWN開始,此時(shí)會(huì)重置所有狀態(tài)与学。
從2014行開始彤悔,對是否攔截的boolean變量進(jìn)行判斷賦值。

如果不攔截:

ViewGroup.dispatchTouchEvent

從2164-2221行就會(huì)對子View進(jìn)行遍歷索守,找到處于點(diǎn)擊范圍的合適的子View晕窑,找到之后,通過2197行的dispatchTransformedTouchEvent方法來調(diào)用child的dispatchTouchEvent方法卵佛,并獲取它的返回值杨赤,根據(jù)返回的值來判斷子View是否成功消耗了事件,如果返回的是true代表成功消費(fèi)截汪,那么就會(huì)對mFirstTouchTarget進(jìn)行賦值疾牲,從而不會(huì)進(jìn)入2238行的條件判斷,不會(huì)調(diào)用super的dispatchTouchEvent方法衙解,事件也就停止了傳遞:

ViewGroup.dispatchTouchEvent

如果child沒有消耗事件阳柔,即child的dispatchTouchEvent方法返回了false,或者沒有發(fā)現(xiàn)合適的子View蚓峦,即child == null舌剂,那么就不會(huì)給mFirstTouchTarget進(jìn)行賦值济锄,即mFirstTouchTarget == null,通過dispatchTransformedTouchEvent方法就會(huì)調(diào)用到super的dispatchTouchEvent方法霍转。

如果進(jìn)行了攔截荐绝,那么直接通過2238行進(jìn)而執(zhí)行2240行,調(diào)用super.dispatchTouchEvent方法谴忧,自己處理事件很泊。

dispatchTransformedTouchEvent的部分源碼如下:

dispatchTransformedTouchEvent

經(jīng)過上述分析,可以知道:
如果不設(shè)置攔截沾谓,MyViewGroupA的直屬child是MyViewGroupB委造,因此MyViewGroupA就會(huì)調(diào)用到MyViewGroupB的dispatchTouchEvent方法,而MyViewGroupB的直屬child是MyView均驶,所以就會(huì)調(diào)用到View的dispatchTouchEvent方法昏兆。
假設(shè)MyViewGroupA或者M(jìn)yViewGroupB設(shè)置了事件攔截,那么就會(huì)調(diào)用ViewGroup的super.dispatchTouchEvent妇穴,而ViewGroup繼承自View爬虱,所以最終還是調(diào)用了View的dispatchTouchEvent方法。

那么接下來就看一下View.dispatchTouchEvent方法:

View.dispatchTouchEvent

可見腾它,上面說的onTouchEvent跑筝、OnTouchListener.onTouch會(huì)被dispatchTouchEvent調(diào)用,不是瞎掰的瞒滴。
通過黃框圈中的代碼可以很明顯的看出View.dispatchTouchEvent的返回值受onTouchEvent曲梗、OnTouchListener.onTouch影響,并且OnTouchListener.onTouch優(yōu)先于onTouchEvent妓忍。

源碼就先看到這里虏两,來捋一下上篇中Log_1所示的流程執(zhí)行:

Log_1

點(diǎn)擊MyView,觸發(fā)ACTION_DOWN
(1) 首先調(diào)用MyViewGroupA.dispatchTouchEvent世剖,在MyViewGroupA.dispatchTouchEvent中調(diào)用MyViewGroupA.onInterceptTouchEvent定罢,返回false,不攔截事件旁瘫;
(2) 找到MyViewGroupA的子View祖凫,即MyViewGroupB,調(diào)用MyViewGroupB.dispatchTouchEvent酬凳,MyViewGroupB.dispatchTouchEvent在執(zhí)行中調(diào)用MyViewGroupB.onInterceptTouchEvent蝙场,返回false,不攔截事件粱年;
(3) 找到MyViewGroupB的子View,即MyView罚拟,調(diào)用MyView.dispatchTouchEvent台诗,由于沒有設(shè)置OnTouchListener完箩,因此在MyView.dispatchTouchEvent中就會(huì)調(diào)用MyView.onTouchEvent,而MyView.onTouchEvent這個(gè)方法返回false拉队,因此就使MyView.dispatchTouchEvent返回false弊知,也就是說,MyView沒有消費(fèi)這個(gè)事件粱快;
(4) 接著秩彤,MyViewGroupB.dispatchTouchEvent中接收到MyView返回的結(jié)果,發(fā)現(xiàn)MyView沒有消費(fèi)事件事哭,mFirstTouchTarget就不會(huì)被賦值漫雷,即mFirstTouchTarget == null,那么根據(jù)ViewGroup.dispatchTouchEvent源碼的第2238行鳍咱,就會(huì)去調(diào)用super.dispatchTouchEvent降盹,進(jìn)而調(diào)用到MyViewGroupB.onTouchEvent這個(gè)方法,而這個(gè)方法返回false谤辜,因此就使MyViewGroupB.dispatchTouchEvent返回false蓄坏,也就是說,MyViewGroupB也沒有消費(fèi)這個(gè)事件丑念;
(5) 最后涡戳,MyViewGroupA.dispatchTouchEvent中接收到MyViewGroupB返回的結(jié)果,發(fā)現(xiàn)MyViewGroupB沒有消費(fèi)事件脯倚,mFirstTouchTarget就不會(huì)被賦值渔彰,即mFirstTouchTarget == null,那么根據(jù)ViewGroup.dispatchTouchEvent源碼的第2238行挠将,就會(huì)去調(diào)用super.dispatchTouchEvent胳岂,進(jìn)而調(diào)用到MyViewGroupA.onTouchEvent這個(gè)方法,自己處理和消費(fèi)事件舔稀。
(注:這個(gè)過程畫圖應(yīng)該會(huì)更清晰乳丰,這里我是按照自己的語言分析順序?qū)懙模哪┑膮⒖兼溄又杏袌D内贮,而且很清晰)

在事件序列中产园,總是以ACTION_DOWN開始,如果不是ACTION_DOWN夜郁,說明事件序列已經(jīng)開始傳遞了什燕。如果對ACTION_DOWN不消費(fèi),那么就可以理解為竞端,我不要這個(gè)事件屎即,也就沒有了接下來ACTION_MOVE、ACTION_UP的傳遞和處理。

這一篇就先分析到這里技俐,太長了看著會(huì)厭煩乘陪,下一篇分析一下onTouchEvent返回true的情況。

參考:
Android事件分發(fā)機(jī)制完全解析雕擂,帶你從源碼的角度徹底理解(上)
Android事件分發(fā)機(jī)制完全解析啡邑,帶你從源碼的角度徹底理解(下)
Android事件分發(fā)機(jī)制詳解
Android群英傳-事件攔截機(jī)制分析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市井赌,隨后出現(xiàn)的幾起案子谤逼,更是在濱河造成了極大的恐慌,老刑警劉巖仇穗,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件流部,死亡現(xiàn)場離奇詭異,居然都是意外死亡仪缸,警方通過查閱死者的電腦和手機(jī)贵涵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來恰画,“玉大人宾茂,你說我怎么就攤上這事∷┗梗” “怎么了跨晴?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長片林。 經(jīng)常有香客問我端盆,道長,這世上最難降的妖魔是什么费封? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任焕妙,我火速辦了婚禮,結(jié)果婚禮上弓摘,老公的妹妹穿的比我還像新娘焚鹊。我一直安慰自己,他們只是感情好韧献,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布末患。 她就那樣靜靜地躺著,像睡著了一般锤窑。 火紅的嫁衣襯著肌膚如雪璧针。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天渊啰,我揣著相機(jī)與錄音探橱,去河邊找鬼申屹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛走搁,可吹牛的內(nèi)容都是我干的独柑。 我是一名探鬼主播,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼私植,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了车酣?” 一聲冷哼從身側(cè)響起曲稼,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎湖员,沒想到半個(gè)月后贫悄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡娘摔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年窄坦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凳寺。...
    茶點(diǎn)故事閱讀 38,768評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鸭津,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出肠缨,到底是詐尸還是另有隱情逆趋,我是刑警寧澤,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布晒奕,位于F島的核電站闻书,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏脑慧。R本人自食惡果不足惜魄眉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望闷袒。 院中可真熱鬧坑律,春花似錦、人聲如沸霜运。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽淘捡。三九已至藕各,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間焦除,已是汗流浹背激况。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人乌逐。 一個(gè)月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓竭讳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親浙踢。 傳聞我的和親對象是個(gè)殘疾皇子绢慢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評論 2 350

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