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

本文由本人原創(chuàng)诚些,轉(zhuǎn)載請注明作者

Android中的事件分發(fā)機(jī)制是新手學(xué)習(xí)的一個(gè)重難點(diǎn)。而且往往學(xué)習(xí)了之后以為掌握的差不多了皇型,但遇到新問題的時(shí)候又發(fā)現(xiàn)沒有掌握到位或者又忘掉了。筆者就是這種情況砸烦,因此將自己已掌握的事件分發(fā)機(jī)制記錄下來弃鸦,作為記錄和交流。

一幢痘、背景目的

  • 什么是Android事件分發(fā)機(jī)制唬格?

事件分發(fā)機(jī)制是處理Android各種滑動(dòng)沖突的理論基礎(chǔ),也是學(xué)習(xí)Android的核心知識(shí)點(diǎn)颜说,掌握好View和ViewGroup的事件分發(fā)機(jī)制是十分重要的购岗。

  • 為什么Android要設(shè)計(jì)一套事件分發(fā)機(jī)制?

當(dāng)父控件和子控件都可以響應(yīng)用戶輸入作出行為的時(shí)候(比如觸摸滑動(dòng))门粪,這時(shí)候就會(huì)造成事件沖突喊积。如何判斷用戶的輸入事件由父控件處理還是子控件處理,就需要設(shè)計(jì)出一套規(guī)則了玄妈,這套規(guī)則就是Android事件分發(fā)機(jī)制乾吻。

  • 沒有子父關(guān)系的控件會(huì)出現(xiàn)事件沖突嗎?

沒有子父關(guān)系的控件拟蜻,它們是不會(huì)產(chǎn)生事件沖突的绎签。因此在處理事件沖突的時(shí)候,首先要分析產(chǎn)生沖突的子控件是哪一個(gè)酝锅,父控件是哪一個(gè)诡必。

二、基礎(chǔ)知識(shí)

  • View和ViewGroup

Android中的控件大致可以分為兩類搔扁,分別是View和ViewGroup爸舒。其中ViewGroup實(shí)際上也是繼承自View。ViewGroup表示可以擁有子控件的控件阁谆,常見的有LinearLayout碳抄、ListView這些。后面我們將通過學(xué)習(xí)知道场绿,在Android事件分發(fā)機(jī)制中剖效,View是沒有攔截方法的,而ViewGroup的攔截方法沒有重寫的話默認(rèn)也是不進(jìn)行攔截的。

  • MotionEvent分類

Android設(shè)備可以接收的事件總類很多璧尸,比如按壓咒林、拖拽、滑動(dòng)爷光,這些事件分類是由android底層完成的垫竞。總的來說蛀序,用戶操作可以分為三類欢瞪,及MotionEvent中的ACTION_DOWN(按下),ACTION_MOVE(移動(dòng))徐裸,ACTION_UP(抬起)遣鼓。從用戶手指按下到抬起這一連串的事件被稱之為一個(gè)事件序列合呐。關(guān)于事件序列犀盟,下面也會(huì)說到龙填。

三菊匿、事件分發(fā)流程

圖片來自網(wǎng)絡(luò)

從這張圖片來看一次點(diǎn)擊事件的傳遞咙咽。在這張圖中有三個(gè)存在子父View關(guān)系的View丧诺,其中上面兩個(gè)能作為父View的自然是屬于ViewGroup了脯颜。

ViewGroup—dispatchTouchEvent方法

Touch事件發(fā)生后悠汽,頂級(jí)父View先接受到消息潜圃,此時(shí)會(huì)先調(diào)用頂級(jí)View的dispatchTouchEvent方法缸棵,這在圖片上沒有畫出來。該方法的返回true的話秉犹,代表事件被消費(fèi)掉了(當(dāng)事件被消費(fèi)時(shí)便不再傳遞)蛉谜;返回false的話事件不再往下傳遞,由上一級(jí)View的onTouchEvent方法來處理崇堵。如果沒有重寫該方法的話(即調(diào)用ViewGroup中的dispatchTouchEvent方法)型诚,會(huì)判斷onInterceptTouchEvent的返回值來確定下一步傳遞方向。

ViewGroup—onInterceptTouchEvent方法

該方法顧名思義鸳劳,判斷當(dāng)前View是否攔截該事件狰贯。如圖所示,返回Ture的話會(huì)攔截事件傳遞赏廓,調(diào)用頂級(jí)View的onTouchEvent方法來處理事件涵紊。返回false的話表示不中斷,事件繼續(xù)向下傳遞幔摸。傳遞到下一級(jí)父View的過程也是一樣摸柄,onInterceptTouchEvent方法返回false的話會(huì)一直向下傳遞到子View。

View-dispatchTouchEvent方法

View的dispatchTouchEvent方法跟ViewGroup是有區(qū)別的既忆。通過看源碼可以知道驱负,View沒有onInterceptTouchEvent方法嗦玖,因此也它會(huì)直接調(diào)用onTouchEvent方法來判斷事件是否被消耗。另外如果View被設(shè)置了各種Listener(如OnClickListener)之后跃脊,對(duì)應(yīng)的事件也會(huì)隨著Listener中對(duì)應(yīng)的方法返回true而被消耗宇挫。

View—onTouchEvent方法

傳遞到子View的時(shí)候會(huì)調(diào)用子View的dispatchTouchEvent方法,一般自定義View的時(shí)候在onTouchEvent中處理與用戶觸摸按壓的交互邏輯酪术。不管該方法過程如何器瘪,如果onTouchEvent的返回值為True表示事件被消耗,事件不再傳遞绘雁。反之橡疼,事件將向上傳遞,傳給父View去處理咧七。另外需要注意的是當(dāng)View的clickable和longClickabale屬性同時(shí)為false的時(shí)候衰齐,代表View不可點(diǎn)擊(如TextView),因此onTouchEvent方法也會(huì)默認(rèn)返回false不消耗事件继阻。

ViewGroup—onTouchEvent方法

ViewGroup對(duì)onTouchEvent的方法和View一樣,返回true的話代表事件被消耗废酷,返回false將事件繼續(xù)向上傳遞瘟檩。具體的行為要看具體的重寫方法。

四澈蟆、總結(jié)分發(fā)流程

可以看到事件傳遞時(shí)是一層層向下傳遞接受墨辛,再由下往上進(jìn)行處理。這和現(xiàn)實(shí)工作也很類似:

產(chǎn)品經(jīng)理提了一個(gè)新的需求趴俘,高級(jí)程序員接到需求先考慮下要不要自己做(onInterceptTouchEvent方法過程)睹簇,覺得應(yīng)該自己處理就自己完成了(ViewGroup—onTouchEvent方法過程);覺得應(yīng)該由下屬去做就下發(fā)給見習(xí)程序員寥闪,見習(xí)程序員沒有下屬只能自己去處理(View—onTouchEvent方法過程)太惠;見習(xí)程序員如果很好地解決需求了(onTouchEvent方法返回true),這個(gè)事件就到此結(jié)束了疲憋。如果需求太難凿渊,見習(xí)程序員處理不了這個(gè)需求(onTouchEvent方法返回false),那么就會(huì)再交給上級(jí)去處理缚柳。

可見Google的程序員在設(shè)計(jì)這些代碼時(shí)的用的方法十分巧妙埃脏,也是和現(xiàn)實(shí)相結(jié)合地去設(shè)計(jì)代碼,對(duì)于開發(fā)者也便于理解秋忙。
任玉剛大神在《Android開發(fā)藝術(shù)探索》一書中對(duì)事件分發(fā)機(jī)制的講解十分到位彩掐,推薦有興趣的朋友去看看。書中用一段偽代碼把事件分發(fā)機(jī)制抽象的非常清楚:

public boolean dispatchTouchEvent(MotionEvent event) {
    boolean consume =false;
    if(onInterceptTouchEvent(ev)) {
        consume = onTouchEvent(ev);
    } else {
        consume = child.dispatchTouchEvent(ev);
    }
    return consume;
}

其中comsume代表事件是否被消耗灰追。當(dāng)事件傳遞到ViewGroup的時(shí)候堵幽,先判斷是否攔截狗超。攔截的話由自己的onTouchEvent方法處理;不攔截的話谐檀,分發(fā)給子View處理抡谐,調(diào)用子View的dispatchTouchEvent方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末桐猬,一起剝皮案震驚了整個(gè)濱河市麦撵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌溃肪,老刑警劉巖免胃,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異惫撰,居然都是意外死亡羔沙,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門厨钻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來扼雏,“玉大人,你說我怎么就攤上這事夯膀∈洌” “怎么了?”我有些...
    開封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵诱建,是天一觀的道長蝴蜓。 經(jīng)常有香客問我,道長俺猿,這世上最難降的妖魔是什么茎匠? 我笑而不...
    開封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮押袍,結(jié)果婚禮上诵冒,老公的妹妹穿的比我還像新娘。我一直安慰自己伯病,他們只是感情好造烁,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著午笛,像睡著了一般惭蟋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上药磺,一...
    開封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天告组,我揣著相機(jī)與錄音,去河邊找鬼癌佩。 笑死木缝,一個(gè)胖子當(dāng)著我的面吹牛便锨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播我碟,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼放案,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了矫俺?” 一聲冷哼從身側(cè)響起吱殉,我...
    開封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎厘托,沒想到半個(gè)月后友雳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铅匹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年押赊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片包斑。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡流礁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出罗丰,到底是詐尸還是另有隱情崇棠,我是刑警寧澤,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布丸卷,位于F島的核電站,受9級(jí)特大地震影響询刹,放射性物質(zhì)發(fā)生泄漏谜嫉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一凹联、第九天 我趴在偏房一處隱蔽的房頂上張望沐兰。 院中可真熱鬧,春花似錦蔽挠、人聲如沸住闯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽比原。三九已至,卻和暖如春杠巡,著一層夾襖步出監(jiān)牢的瞬間量窘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來泰國打工氢拥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蚌铜,地道東北人锨侯。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像冬殃,于是被迫代替她去往敵國和親囚痴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

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