了解Android Touch事件傳遞機(jī)制

MotionEvent

每一次用戶Touch事件都會被包裝為一個(gè)MotionEvent對象购对,對象中包含關(guān)于這個(gè)事件你想要的全部信息噪猾,包括事件所產(chǎn)生的動(dòng)作(ACTION_DOWN掌呜、ACTION_MOVE疗绣、ACTION_UP侦另、ACTION_CANCEL等)岁疼、事件產(chǎn)生的位置坐標(biāo)、事件發(fā)生時(shí)屏幕上手指的數(shù)量和時(shí)間的發(fā)生時(shí)間等晨逝。
在Android中蛾默,一個(gè)手勢(gesture)的定義是一組開始于ACTION_DOWN并結(jié)束于ACTION_UP的事件集合。

Touch事件傳遞

對于每一個(gè)由硬件和底層框架產(chǎn)生的事件捉貌,這些事件會首先被發(fā)送到當(dāng)前顯示的Activity中支鸡,這個(gè)過程是由框架調(diào)用Activity的dispatchTouchEvent()來實(shí)現(xiàn)的,不管你在程序中做了何種事件處理趁窃,Activity的dispatchTouchEvent()都會是Event被處理的第一站牧挣。在這個(gè)方法里,Event將開始由上到下被傳遞棚菊,從rootView依次往下傳遞直到視圖樹的最底部浸踩,之后,事件會反過來以冒泡的方式向上傳遞统求。這里的傳遞機(jī)制是事件會在程序中從上往下再從下往上穿梭检碗,直到某個(gè)View宣布其對這個(gè)事件感興趣為止。是否感興趣取決于View的onTouchEvent()方法是否返回了true码邻。
當(dāng)嘗試做自定義事件處理時(shí)折剃,ACTION_DOWN事件需要被關(guān)注的,如果你對ACTION_DOWN后續(xù)發(fā)生的事件感興趣像屋,就需要在onTouchEvent()中返回true怕犁。Android系統(tǒng)認(rèn)為如果你對手勢中的ACTION_DOWN事件不感興趣,那么你對這一手勢中的其他事件亦不會感興趣己莺,一旦表示對ACTION_DOWN感興趣奏甫,那么手勢中的其他事件便會以此View為直接目的地。
總結(jié)一下凌受,事件在視圖樹中的傳遞方式就是從rootView開始自頂向下傳遞阵子,根據(jù)各層是ViewGroup還是View調(diào)用各自的dispatchTouchEvent()方法,ViewGroup會把事件遞歸地傳遞給它的child胜蛉。接下來挠进,事件從下往上傳遞時(shí)色乾,會調(diào)用ViewGroup和View的onTouchEvent()。所以领突,Activity中的onTouchEvent()是最后被調(diào)用到的暖璧,如果已經(jīng)有子View的onTouchEvent()返回了true,那么Activity的onTouchEvent()則根本不會被調(diào)用君旦。另外我們可以使用TouchListener來處理觸摸事件澎办,并返回true表示已經(jīng)消費(fèi)了該事件。
下面我們來梳理各個(gè)組件在事件傳遞流程中所承擔(dān)的工作金砍。

Activity

dispatchTouchEvent()

該方法總是在事件發(fā)生時(shí)最先被調(diào)用到浮驳;
執(zhí)行后會將Event發(fā)送給Window,再由Window發(fā)送給DecorView捞魁,最后傳遞到用戶自定義的RootView(通常是一個(gè)ViewGroup)并觸發(fā)RootView的dispatchTouchEvent()

onTouchEvent()

在整個(gè)視圖樹中沒有View消費(fèi)了事件的時(shí)候被調(diào)用离咐;
事件傳遞的終點(diǎn)谱俭,總是最后被調(diào)用(如果可能)。

View

dispatchTouchEvent()

如果存在TouchListener宵蛀,則將Event發(fā)送給執(zhí)行listener.onTouch()昆著;
如果不存在TouchListenerlistener.onTouch()沒有返回true,則自己處理該事件术陶,即調(diào)用自身的onTouchEvent()凑懂。

onTouchEvent()

如果返回false,則將Event向上冒泡梧宫,并且該View不再能接受當(dāng)前手勢中的后續(xù)事件接谨。

ViewGroup

dispatchTouchEvent()

對childView進(jìn)行遍歷和迭代,以確定哪些child可能對事件感興趣(根據(jù)當(dāng)前觸摸位置判斷)塘匣,如果觸摸位置位于多個(gè)child邊界范圍內(nèi)脓豪,則按照被加入到ViewGroup的順序的逆序遍歷這些child,讓child有處理事件的機(jī)會忌卤。
對事件進(jìn)行中斷或竊取扫夜,通過onInterceptTouchEvent()

onInterceptTouchEvent()

此方法在不斷監(jiān)控觸摸事件,在需要滿足該ViewGroup特殊需求的時(shí)候中斷將事件分發(fā)給原本要消費(fèi)事件的childView驰徊,轉(zhuǎn)而讓自己來處理這些事件笤闯,通常在ViewGroup自身要根據(jù)手勢進(jìn)行滾動(dòng)等操作的時(shí)候調(diào)用此方法,調(diào)用此方法可能會向childView傳遞ACTION_CANCEL事件棍厂。

requestDisallowInterceptTouchEvent()

由父視圖調(diào)用颗味,用來打斷onInterceptTouchEvent()的邏輯。通常勋桶,事件都是由ViewGroup先監(jiān)測脱衙,再決定是否分發(fā)到childView中侥猬,同時(shí)也由ViewGroup決定是否屏蔽其childView的事件。但是捐韩,當(dāng)childView需要決定父視圖是否可以屏蔽觸摸事件(不管是暫時(shí)還是永久)時(shí)退唠,就需要調(diào)用此方法。如果傳入true荤胁,則剝奪父視圖中斷此事件的能力瞧预。當(dāng)ACTION_UP事件發(fā)生時(shí),前一次調(diào)用requestDisallowInterceptTouchEvent()設(shè)置的狀態(tài)會失效仅政。通常垢油,在ViewPager的頁面中嵌入可以橫向滑動(dòng)的View時(shí)你會需要調(diào)用此方法來確保滑動(dòng)View時(shí)不會引起ViewPager的頁面切換圆丹。

Attention

除非真的有必要滩愁,否則盡量不要重寫dispatchTouchEvent()方法,如果進(jìn)行了重寫辫封,則必須調(diào)用super.dispatchTouchEvent()方法硝枉,否則事件分發(fā)過程會在此中斷。
當(dāng)dispatchTouchEvent返回true時(shí)倦微,表示在此時(shí)Event已經(jīng)被處理妻味,事件傳遞到此為止,返回false時(shí)欣福,如果事件來自于Activity责球,則將事件交給Activity的onTouchEvent()處理,如果來自于父View拓劝,則將事件交給父View的onTouchEvent()處理
一旦View的onTouchEvent在處理手勢中的某一Event時(shí)返回了false雏逾,則該手勢中的后續(xù)事件不會再到達(dá)該View

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市凿将,隨后出現(xiàn)的幾起案子校套,更是在濱河造成了極大的恐慌,老刑警劉巖牧抵,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件笛匙,死亡現(xiàn)場離奇詭異,居然都是意外死亡犀变,警方通過查閱死者的電腦和手機(jī)妹孙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來获枝,“玉大人蠢正,你說我怎么就攤上這事∈〉辏” “怎么了嚣崭?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵笨触,是天一觀的道長。 經(jīng)常有香客問我雹舀,道長芦劣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任说榆,我火速辦了婚禮虚吟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘签财。我一直安慰自己串慰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布唱蒸。 她就那樣靜靜地躺著邦鲫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪神汹。 梳的紋絲不亂的頭發(fā)上掂碱,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機(jī)與錄音慎冤,去河邊找鬼。 笑死沧卢,一個(gè)胖子當(dāng)著我的面吹牛蚁堤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播但狭,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼披诗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了立磁?” 一聲冷哼從身側(cè)響起呈队,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎唱歧,沒想到半個(gè)月后宪摧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡颅崩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年几于,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沿后。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沿彭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出尖滚,到底是詐尸還是另有隱情喉刘,我是刑警寧澤瞧柔,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站睦裳,受9級特大地震影響造锅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜推沸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一备绽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鬓催,春花似錦肺素、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至课舍,卻和暖如春塌西,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背筝尾。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工捡需, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人筹淫。 一個(gè)月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓站辉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親损姜。 傳聞我的和親對象是個(gè)殘疾皇子饰剥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348

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