觸摸事件之事件分發(fā)

上篇文章中,分析了我之前關(guān)于觸摸事件的一點(diǎn)疑問(wèn),感興趣的夺衍,可點(diǎn)擊觸摸事件之onTouch和onTouchEvent查看

趁著熱乎勁兒,繼續(xù)再來(lái)鞏固下完整的事件分發(fā)流程吧喜命。
先不回憶細(xì)節(jié)沟沙,單純從最簡(jiǎn)單的角度來(lái)看,事件分發(fā)無(wú)非就3步:事件產(chǎn)生->事件傳遞->事件處理壁榕。就跟春晚小品宋丹丹問(wèn)趙大叔把大象放進(jìn)冰箱分幾步一個(gè)道理矛紫。從最原始的角度出發(fā)來(lái)看待這個(gè)問(wèn)題,中間的過(guò)程再逐步細(xì)化护桦,這樣大腦中有個(gè)清晰的流程含衔,分析問(wèn)題也會(huì)順暢的多。

從手指觸摸屏幕的那一刻二庵,觸摸事件便產(chǎn)生了,拋開(kāi)硬件層面的電容電流感應(yīng)缓呛,到應(yīng)用層的APP層面催享,最先肯定是由Activity接收到事件,咱們來(lái)瞧瞧Activity里面的處理過(guò)程哟绊;

 public boolean dispatchTouchEvent(MotionEvent ev) {
        //...
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

里面有行代碼很關(guān)鍵因妙,“getWindow().superDispatchTouchEvent(ev)”,事件由window分發(fā)票髓,如果返回true,后面的onTouchEvent將不執(zhí)行攀涵,怎么感覺(jué)這句話(huà)很熟悉?洽沟?原來(lái)上篇文章剛分析過(guò)類(lèi)似的以故。繼續(xù)追查這個(gè)window是什么,原來(lái)是:

mWindow = new PhoneWindow(this, window, activityConfigCallback);

熟悉安卓界面加載的都知道裆操,phoneWindow跟DecorView密切相關(guān)怒详,莫非window將事件傳給了DecorView,繼續(xù)看源碼:

 @Override
public boolean superDispatchTouchEvent(MotionEvent event) {
    return mDecor.superDispatchTouchEvent(event);
}

果然踪区,一切盡在預(yù)料之中啊昆烁,這種感覺(jué)很爽。DecorView中分發(fā)過(guò)程也很簡(jiǎn)單缎岗,

    public boolean superDispatchTouchEvent(MotionEvent event) {
        return super.dispatchTouchEvent(event);
    }

DecorView是一個(gè)FrameLayout布局静尼,它由上下兩部分組成,上面是actionBar,下面是我們最最親愛(ài)的在setContentView()方法中傳進(jìn)xml布局文件鼠渺,生成的視圖組鸭巴。上面的事件已經(jīng)分發(fā)至DecorView了,現(xiàn)在我們將樣式設(shè)為為noActionBar系冗,那么DecorView布局中就只有一個(gè)contentView布局奕扣。在上面的方法中,由于FrameLayout沒(méi)有重寫(xiě)分發(fā)方法掌敬,所以會(huì)接著向上查找分發(fā)方法惯豆,最終找到ViewGroup中的dispatchTouchEvent方法,而這個(gè)viewGroup中的第一個(gè)子view就是contentView生成的視圖組奔害。接下來(lái)看看viewGroup中的分發(fā)方法楷兽。

for (int i = childrenCount - 1; i >= 0; i--) {
//...
        if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
             // Child wants to receive touch within its bounds.
             mLastTouchDownTime = ev.getDownTime();
        }
//...
}

代碼很長(zhǎng),挑關(guān)鍵的看华临,看到for循環(huán)芯杀,知道重頭戲來(lái)了,我們知道DecorView作為所有Activity根視圖的外層容器雅潭,一個(gè)Activity界面就是有一個(gè)個(gè)ViewGroup不斷包含子View構(gòu)成的揭厚,在ViewGroup里對(duì)所有子view進(jìn)行遍歷,肯定也會(huì)遍歷傳遞處理觸摸事件扶供,我們找child和touchEvent兩個(gè)關(guān)鍵字筛圆,找到一個(gè)方法
“dispatchTransformedTouchEvent”,進(jìn)去看一下:

    private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
            View child, int desiredPointerIdBits) {
        final boolean handled;

        // Canceling motions is a special case.  We don't need to perform any transformations
        // or filtering.  The important part is the action, not the contents.
        final int oldAction = event.getAction();
        if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
            event.setAction(MotionEvent.ACTION_CANCEL);
            if (child == null) {
                handled = super.dispatchTouchEvent(event);
            } else {
                handled = child.dispatchTouchEvent(event);
            }
            event.setAction(oldAction);
            return handled;
        }
       //...
}

期待已久的child.dispatchTouchEvent(event)出現(xiàn)了4慌ā太援!出現(xiàn)了!扳碍!截止到目前為止提岔,根據(jù)我們所掌握的信息,可以很肯定的是笋敞,\color{#FF0000}{觸摸事件從Activity開(kāi)始碱蒙,沿著最頂層DecorView,一路往下分發(fā)下去液样。}

根據(jù)child類(lèi)型的不同振亮,dispatchTouchEvent實(shí)現(xiàn)肯定也不同,view類(lèi)型的不細(xì)說(shuō)了鞭莽,直接貼代碼吧:

public boolean dispatchTouchEvent(MotionEvent event) {
//...
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }
//...
}

ViewGroup相比于View肯定要復(fù)雜些坊秸,其內(nèi)部多了要處理子view的情況,在這里貼上一位網(wǎng)友制作的圖澎怒,個(gè)人認(rèn)為很不錯(cuò):


ViewGroup分發(fā)流程

途中很清晰的描繪了viewgroup是如何把事件傳遞給子view的褒搔,onInterceptTouchEvent是viewGroup中獨(dú)有的方法阶牍,它的返回值直接決定了是否會(huì)將事件傳遞給子view處理。如果子 View 不處理星瘾,這個(gè)“鍋”就得 ViewGroup 自己擔(dān)著走孽。所以事件會(huì)傳遞到 super.dispatchTouchEvent()。ViewGroup 類(lèi)繼承自 View 類(lèi)琳状,也就是進(jìn)入了前文說(shuō)的 View 事件分發(fā)流程磕瓷,就相當(dāng)于詢(xún)問(wèn)當(dāng)前 ViewGroup 自己是否處理這個(gè)事件,細(xì)節(jié)這里就不重復(fù)了念逞。如果當(dāng)前 ViewGroup自己處理了困食,對(duì)于上級(jí) ViewGroup 而言,還是找到了 target翎承,如果當(dāng)前 ViewGroup 不處理硕盹,這個(gè)“鍋”繼續(xù)拋給上級(jí) ViewGroup。

當(dāng)最外層的子view接收到分發(fā)事件時(shí)叨咖,會(huì)進(jìn)入它自身的dispatchTouchEvent方法瘩例,當(dāng)它不攔截時(shí),事件會(huì)繼續(xù)進(jìn)入到onTouchEvent方法中處理甸各,然后再一級(jí)一級(jí)向上傳遞返回值垛贤。

以上就是觸摸事件分發(fā)流程的簡(jiǎn)要分析,源碼也一直在更新趣倾。掌握了主要的流程南吮,任他怎么改,也能做到心中有數(shù)誊酌。

參考:
通過(guò)流程圖來(lái)分析Android事件分發(fā)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市露乏,隨后出現(xiàn)的幾起案子碧浊,更是在濱河造成了極大的恐慌,老刑警劉巖瘟仿,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件箱锐,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡劳较,警方通過(guò)查閱死者的電腦和手機(jī)驹止,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)观蜗,“玉大人臊恋,你說(shuō)我怎么就攤上這事∧鼓恚” “怎么了抖仅?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我撤卢,道長(zhǎng)环凿,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任放吩,我火速辦了婚禮智听,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘渡紫。我一直安慰自己到推,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布腻惠。 她就那樣靜靜地躺著环肘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪集灌。 梳的紋絲不亂的頭發(fā)上悔雹,一...
    開(kāi)封第一講書(shū)人閱讀 51,208評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音欣喧,去河邊找鬼腌零。 笑死,一個(gè)胖子當(dāng)著我的面吹牛唆阿,可吹牛的內(nèi)容都是我干的益涧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼驯鳖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼闲询!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起浅辙,我...
    開(kāi)封第一講書(shū)人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤扭弧,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后记舆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鸽捻,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年泽腮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了御蒲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诊赊,死狀恐怖厚满,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情豪筝,我是刑警寧澤痰滋,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布摘能,位于F島的核電站,受9級(jí)特大地震影響敲街,放射性物質(zhì)發(fā)生泄漏团搞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一多艇、第九天 我趴在偏房一處隱蔽的房頂上張望逻恐。 院中可真熱鬧,春花似錦峻黍、人聲如沸复隆。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)挽拂。三九已至,卻和暖如春骨饿,著一層夾襖步出監(jiān)牢的瞬間亏栈,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工宏赘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绒北,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓察署,卻偏偏與公主長(zhǎng)得像闷游,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子贴汪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354