android的touch事件分發(fā)響應(yīng)機(jī)制

想要弄明白android的touch事件分發(fā)響應(yīng)機(jī)制需要先充分理解一下幾個(gè)知識(shí)點(diǎn):

  • View和ViewGroup
  • touch事件的構(gòu)成
  • ViewGroup如何對(duì)事件分發(fā)和攔截
  • View和ViewGroup如何對(duì)事件進(jìn)行響應(yīng)

View和ViewGroup

  • 先看一下官方文檔對(duì)view類的部分介紹

View is the base class for widgets, which are used to create interactive UI components (buttons, text fields, etc.). The ViewGroup subclass is the base class for layouts, which are invisible containers that hold other Views (or other ViewGroups) and define their layout properties.

從這里我們就可以看出View是android中所有界面布局組件的基類匕得,而ViewGroup 是View的一個(gè)子類,ViewGroup是一個(gè)容器類巾表,可以往里面添加子View汁掠。

  • 再看一下android的界面是如何構(gòu)成的
    這里有一篇官方文檔UI Overview
    下面是該文章中的一部分內(nèi)容:

All user interface elements in an Android app are built using View
and ViewGroup objects. A View is an object that draws something on the screen that the user can interact with. A ViewGroup is an object that holds other View (and ViewGroup) objects in order to define the layout of the interface.

Android provides a collection of both View and ViewGroup subclasses that offer you common input controls (such as buttons and text fields) and various layout models (such as a linear or relative layout).

User Interface Layout

上面的內(nèi)容大概告訴大家android的界面的布局是一個(gè)樹(shù)狀的層級(jí)結(jié)構(gòu)摩窃。
由頂級(jí)的ViewGroup其中包含一個(gè)或者多個(gè)View和ViewGroup來(lái)實(shí)現(xiàn)的隆敢。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout  
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent"    
  android:orientation="vertical">    
  <TextView        
    android:id="@+id/text"        
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"        
    android:text="I am a TextView" />    
  <Button     
    android:id="@+id/button"         
    android:layout_width="wrap_content"  
    android:layout_height="wrap_content"        
    android:text="I am a Button" />    
</LinearLayout>

這時(shí)候我們是不是得思考一下了,View和ViewGroup在界面布局的時(shí)候作用是不一樣的粘姜,那么在touch事件的分發(fā)及響應(yīng)上是不是也不一樣呢鞠苟。


touch事件的構(gòu)成

在Android中乞榨,事件主要包括點(diǎn)按秽之、長(zhǎng)按、拖拽吃既、滑動(dòng)等考榨,點(diǎn)按又包括單擊和雙擊,另外還包括單指操作和多指操作鹦倚。所有這些都構(gòu)成了Android中的事件響應(yīng)河质。總的來(lái)說(shuō)震叙,所有的事件都由如下三個(gè)ACTION作為基礎(chǔ):

  • 按下(ACTION_DOWN)
  • 移動(dòng)(ACTION_MOVE)
  • 抬起(ACTION_UP)

所有的touch事件首先必須執(zhí)行的是按下操作(ACTION_DOWN)掀鹅,之后所有的操作都是以按下操作作為前提,當(dāng)按下操作完成后捐友,接下來(lái)可能是一段移動(dòng)(ACTION_MOVE)然后抬起(ACTION_UP)淫半,或者是按下操作執(zhí)行完成后沒(méi)有移動(dòng)就直接抬起溃槐。

事件分發(fā)攔截以及響應(yīng)

下面就開(kāi)始本文的重點(diǎn)內(nèi)容了:事件的分發(fā)和攔截匣砖。
說(shuō)到分發(fā)和攔截,就拿上面xml中那個(gè)布局來(lái)說(shuō)昏滴,Button已經(jīng)是界面層級(jí)中最末端的元素了猴鲫,所以它已經(jīng)無(wú)法再把touch事件往下傳遞了,所以事件的分發(fā)和攔截其實(shí)是對(duì)ViewGroup來(lái)說(shuō)的(有子view才需要把事件往下傳遞給子view或者攔截掉事件自己處理)谣殊。
這里主要牽涉到2個(gè)方法:

  • public boolean dispatchTouchEvent (MotionEvent event)
    從下面的方法描述中可以看出這個(gè)方法是用來(lái)分發(fā)事件的


  • public boolean onInterceptTouchEvent (MotionEvent event)
    從下面的方法描述中可以看出這個(gè)方法是用來(lái)攔截事件的


    需要注意的是onInterceptTouchEvent方法是ViewGroup的方法拂共,View沒(méi)有。

Touch事件的響應(yīng)式通過(guò)下面的方法來(lái)實(shí)現(xiàn)的:

  • public boolean onTouchEvent (MotionEvent event)
    返回true代表自己消費(fèi)了這個(gè)事件


涉及到的3個(gè)方法都講過(guò)了姻几,那么下面來(lái)講一下事件分發(fā)傳遞及響應(yīng)的流程宜狐。

  1. 事件分發(fā)流程
    從上到下,從父到子:Activity->ViewGroup1->ViewGroup1的子ViewGroup2->…->Target View
  2. 事件響應(yīng)流程
    從下到上蛇捌,從子到父:Target View->…->ViewGroup1的子ViewGroup2->ViewGroup1->Activity

上面是一個(gè)簡(jiǎn)單的描述抚恒,下面我們通過(guò)例子來(lái)了解詳細(xì)的流程。

自定義一個(gè)ParentLayout 繼承RelativeLayout络拌;再自定義一個(gè)CustomImageView繼承ImageView俭驮。

  • 對(duì)ParentLayout來(lái)說(shuō)實(shí)現(xiàn)它的dispatchTouchEvent ,onInterceptTouchEvent以及onTouchEvent方法春贸,并在其中打印輸出接收到的事件

  • 對(duì)CustomImageView來(lái)說(shuō)實(shí)現(xiàn)它的onTouchEvent方法混萝,并在其中打印輸出接收到的事件

界面效果圖:
點(diǎn)擊左側(cè)汪星人的效果。


左側(cè)的圖片設(shè)置了onclick事件萍恕,所以他的touch事件是可以消費(fèi)的逸嘀。

16:04:53.172   D/MainActivity.dispatchTouchEvent(MainActivity.java:47)﹕ ACTION_DOWN
16:04:53.177   D/ParentLayout.dispatchTouchEvent(ParentLayout.java:35)﹕ ACTION_DOWN
16:04:53.177   D/ParentLayout.onInterceptTouchEvent(ParentLayout.java:59)﹕ ACTION_DOWN
16:04:53.177   E/ParentLayout.onInterceptTouchEvent(ParentLayout.java:73)﹕ return false
16:04:53.182   D/CustomImageView.onTouchEvent(CustomImageView.java:35)﹕ ACTION_DOWN
16:04:53.182   E/CustomImageView.onTouchEvent(CustomImageView.java:49)﹕ return true
16:04:53.182   E/ParentLayout.dispatchTouchEvent(ParentLayout.java:49)﹕ return true
16:04:53.182   D/ParentLayout.dispatchTouchEvent(ParentLayout.java:40)﹕ ACTION_MOVE
16:04:53.187   D/ParentLayout.onInterceptTouchEvent(ParentLayout.java:64)﹕ ACTION_MOVE
16:04:53.197   E/ParentLayout.onInterceptTouchEvent(ParentLayout.java:73)﹕ return false
16:04:53.197   D/CustomImageView.onTouchEvent(CustomImageView.java:40)﹕ ACTION_MOVE
16:04:53.197   E/CustomImageView.onTouchEvent(CustomImageView.java:49)﹕ return true
16:04:53.197   E/ParentLayout.dispatchTouchEvent(ParentLayout.java:49)﹕ return true
16:04:53.217   D/ParentLayout.dispatchTouchEvent(ParentLayout.java:40)﹕ ACTION_MOVE
16:04:53.217   D/ParentLayout.onInterceptTouchEvent(ParentLayout.java:64)﹕ ACTION_MOVE
16:04:53.222   E/ParentLayout.onInterceptTouchEvent(ParentLayout.java:73)﹕ return false
16:04:53.222   D/CustomImageView.onTouchEvent(CustomImageView.java:40)﹕ ACTION_MOVE
16:04:53.222   E/CustomImageView.onTouchEvent(CustomImageView.java:49)﹕ return true
16:04:53.227   E/ParentLayout.dispatchTouchEvent(ParentLayout.java:49)﹕ return true
16:04:53.237   D/ParentLayout.dispatchTouchEvent(ParentLayout.java:40)﹕ ACTION_MOVE
16:04:53.237   D/ParentLayout.onInterceptTouchEvent(ParentLayout.java:64)﹕ ACTION_MOVE
16:04:53.247   E/ParentLayout.onInterceptTouchEvent(ParentLayout.java:73)﹕ return false
16:04:53.257   D/CustomImageView.onTouchEvent(CustomImageView.java:40)﹕ ACTION_MOVE
16:04:53.267   E/CustomImageView.onTouchEvent(CustomImageView.java:49)﹕ return true
16:04:53.277   E/ParentLayout.dispatchTouchEvent(ParentLayout.java:49)﹕ return true
16:04:53.287   D/ParentLayout.dispatchTouchEvent(ParentLayout.java:40)﹕ ACTION_MOVE
16:04:53.292   D/ParentLayout.onInterceptTouchEvent(ParentLayout.java:64)﹕ ACTION_MOVE
16:04:53.322   E/ParentLayout.onInterceptTouchEvent(ParentLayout.java:73)﹕ return false
16:04:53.327   D/CustomImageView.onTouchEvent(CustomImageView.java:40)﹕ ACTION_MOVE
16:04:53.327   E/CustomImageView.onTouchEvent(CustomImageView.java:49)﹕ return true
16:04:53.327   E/ParentLayout.dispatchTouchEvent(ParentLayout.java:49)﹕ return true
16:04:53.327   D/MainActivity.dispatchTouchEvent(MainActivity.java:51)﹕ ACTION_UP
16:04:53.332   D/ParentLayout.dispatchTouchEvent(ParentLayout.java:43)﹕ ACTION_UP
16:04:53.332   D/ParentLayout.onInterceptTouchEvent(ParentLayout.java:67)﹕ ACTION_UP
16:04:53.332   E/ParentLayout.onInterceptTouchEvent(ParentLayout.java:73)﹕ return false
16:04:53.337   D/CustomImageView.onTouchEvent(CustomImageView.java:43)﹕ ACTION_UP
16:04:53.337   E/CustomImageView.onTouchEvent(CustomImageView.java:49)﹕ return true
16:04:53.337   E/ParentLayout.dispatchTouchEvent(ParentLayout.java:49)﹕ return true
16:04:53.342   I/MainActivity.clickImage(MainActivity.java:133)﹕ clickImage

點(diǎn)擊左側(cè)喵星人的效果。


右側(cè)的喵星人沒(méi)有設(shè)置事件監(jiān)聽(tīng)允粤,所以他沒(méi)有對(duì)此次Touch事件消費(fèi)崭倘,事件又向上傳遞回了ParentLayout的onTouchEvent屯蹦。

16:12:24.882   D/MainActivity.dispatchTouchEvent(MainActivity.java:47)﹕ ACTION_DOWN
16:12:24.882   D/ParentLayout.dispatchTouchEvent(ParentLayout.java:35)﹕ ACTION_DOWN
16:12:24.882   D/ParentLayout.onInterceptTouchEvent(ParentLayout.java:59)﹕ ACTION_DOWN
16:12:24.887   E/ParentLayout.onInterceptTouchEvent(ParentLayout.java:73)﹕ return false
16:12:24.887   D/CustomImageView.onTouchEvent(CustomImageView.java:35)﹕ ACTION_DOWN
16:12:24.887   E/CustomImageView.onTouchEvent(CustomImageView.java:49)﹕ return false
16:12:24.892   D/ParentLayout.onTouchEvent(ParentLayout.java:83)﹕ ACTION_DOWN
16:12:24.892   E/ParentLayout.onTouchEvent(ParentLayout.java:97)﹕ return false
16:12:24.892   E/ParentLayout.dispatchTouchEvent(ParentLayout.java:49)﹕ return false
16:12:24.922   D/MainActivity.dispatchTouchEvent(MainActivity.java:51)﹕ ACTION_UP

TODO 此次只是分析了touch事件簡(jiǎn)單流程。后續(xù)有時(shí)間再去分析這三個(gè)方法如果返回不同的值會(huì)對(duì)事件的分發(fā)和響應(yīng)有什么影響绳姨。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末登澜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子飘庄,更是在濱河造成了極大的恐慌脑蠕,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跪削,死亡現(xiàn)場(chǎng)離奇詭異谴仙,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)碾盐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門晃跺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人毫玖,你說(shuō)我怎么就攤上這事掀虎。” “怎么了付枫?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵烹玉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我阐滩,道長(zhǎng)二打,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任掂榔,我火速辦了婚禮继效,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘装获。我一直安慰自己瑞信,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布饱溢。 她就那樣靜靜地躺著喧伞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绩郎。 梳的紋絲不亂的頭發(fā)上潘鲫,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音肋杖,去河邊找鬼溉仑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛状植,可吹牛的內(nèi)容都是我干的浊竟。 我是一名探鬼主播怨喘,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼振定!你這毒婦竟也來(lái)了必怜?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤后频,失蹤者是張志新(化名)和其女友劉穎梳庆,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體卑惜,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡膏执,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了露久。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片更米。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖毫痕,靈堂內(nèi)的尸體忽然破棺而出征峦,到底是詐尸還是另有隱情,我是刑警寧澤镇草,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布眶痰,位于F島的核電站,受9級(jí)特大地震影響梯啤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜存哲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一因宇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧祟偷,春花似錦察滑、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至嵌施,卻和暖如春饲化,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吗伤。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工吃靠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人足淆。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓巢块,卻偏偏與公主長(zhǎng)得像礁阁,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子族奢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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