ViewGroup源碼-Touch事件

在Android-27中查看源碼:

在看完View源碼的觸摸事件(參考文章:View源碼-Touch事件)后,我們接著來看看容器類View的觸摸事件土榴。因?yàn)槿萜黝惖腣iew都繼承自ViewGroup,所以我們?cè)赩iewGroup的源碼中來看看是如何處理觸摸事件的艰毒。

同樣的先來看ViewGroup源碼中的dispatchTouchEvent方法:

final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
    final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
    if (!disallowIntercept) {
        intercepted = onInterceptTouchEvent(ev);
        ev.setAction(action); // restore action in case it was changed
    } else {
        intercepted = false;
    }
} else {
    // There are no touch targets and this action is not an initial down
    // so this view group continues to intercept touches.
    intercepted = true;
}

首先愤诱,會(huì)判斷是否不允許攔截,可以通過requestDisallowInterceptTouchEvent進(jìn)行設(shè)置酒请,默認(rèn)允許攔截。如果允許攔截鸣个,會(huì)調(diào)用onInterceptTouchEvent羞反,看看該View是否攔截了觸摸事件布朦,默認(rèn)不攔截即可以將觸摸事件向子View傳遞。

接下來昼窗,如果觸摸事件沒有取消并且沒有攔截是趴,在手指按下的時(shí)候:

final ArrayList<View> preorderedList = buildTouchDispatchChildList();
...
for (int i = childrenCount - 1; i >= 0; i--){
    ...
    newTouchTarget = getTouchTarget(child);
    if (newTouchTarget != null) {
        // Child is already receiving touch within its bounds.
        // Give it the new pointer in addition to the ones it is handling.
        newTouchTarget.pointerIdBits |= idBitsToAssign;
        break;
    }
    resetCancelNextUpFlag(child);
    if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
        // Child wants to receive touch within its bounds.
        mLastTouchDownTime = ev.getDownTime();
        if (preorderedList != null) {
            // childIndex points into presorted list, find original index
            for (int j = 0; j < childrenCount; j++) {
                if (children[childIndex] == mChildren[j]) {
                    mLastTouchDownIndex = j;
                    break;
                }
            }
        } else {
            mLastTouchDownIndex = childIndex;
        }
        mLastTouchDownX = ev.getX();
        mLastTouchDownY = ev.getY();
        newTouchTarget = addTouchTarget(child, idBitsToAssign);
        alreadyDispatchedToNewTouchTarget = true;
        break;
    }
...
}
  1. 按照繪制子View的順序,找到該ViewGoup的所有子view澄惊,并保存到ArrayList中唆途。
  2. 根據(jù)視圖順序依次遍歷子View。判斷當(dāng)前子view是否是TouchTarget掸驱,若是則跳出循環(huán)肛搬。否則調(diào)用dispatchTransformedTouchEvent方法,如果當(dāng)前子View的dispatchTouchEvent返回為true,找到該子View在ViewGroup中的index,并將該子View作為新的TouchTarget毕贼。
  3. 清楚保存了所有子View的ArrayList温赔。

然后在TouchTarget形成的鏈?zhǔn)浇Y(jié)構(gòu)中,處理觸摸事件:

// Dispatch to touch targets.
if (mFirstTouchTarget == null) {
    // No touch targets so treat this as an ordinary view.
    handled = dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS);
} else {
    // Dispatch to touch targets, excluding the new touch target if we already
    // dispatched to it.  Cancel touch targets if necessary.
    TouchTarget predecessor = null;
    TouchTarget target = mFirstTouchTarget;
    while (target != null) {
        final TouchTarget next = target.next;
        if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
            handled = true;
        } else {
            final boolean cancelChild = resetCancelNextUpFlag(target.child) || intercepted;
            if (dispatchTransformedTouchEvent(ev, cancelChild,target.child, target.pointerIdBits)) {
                handled = true;
            }
            if (cancelChild) {
                if (predecessor == null) {
                    mFirstTouchTarget = next;
                } else {
                    predecessor.next = next;
                }
                target.recycle();
                target = next;
                continue;
            }
        }
        predecessor = target;
        target = next;
    }
}
  1. 如果子View沒有處理觸摸事件鬼癣,則由當(dāng)前的ViewGroup處理让腹,然后返回處理結(jié)果。因?yàn)閂iewGroup是View的子類扣溺,所以還是由View的dispatchTouchEvent處理。
  2. 如果子View中處理了觸摸事件瓜晤,根據(jù)TouchTarget生成的鏈?zhǔn)浇Y(jié)構(gòu)锥余,不斷循環(huán),分別調(diào)用里面View的dispatchTouchEvent方法痢掠。

從上面的分析可以看出整個(gè)ViewGroup的Touch事件的整個(gè)傳遞過程如下:

  1. 是否調(diào)用了requestDisallowInterceptTouchEvent方法設(shè)置不允許攔截驱犹,默認(rèn)允許攔截。若允許攔截足画,則再調(diào)用onInterceptTouchEvent,看是否攔截雄驹。
  2. 如果觸摸事件被攔截,則調(diào)用ViewGroup的dispatchTransformedTouchEvent方法淹辞,其實(shí)是調(diào)用View的dispatchTouchEvent方法医舆。否則繼續(xù)向下。
  3. 當(dāng)觸摸事件為MotionEvent.ACTION_DOWN時(shí)象缀,首先獲取根據(jù)繪制順序保存了所有子View的ArrayLsit蔬将,然后再根據(jù)視圖順序去遍歷子View。
    i. 如果從TouchTarget形成的鏈表中發(fā)現(xiàn)該View,則跳出循環(huán)央星,即找到了TouchTarget霞怀。否則繼續(xù)向下。
    ii. 在子View中尋找莉给,當(dāng)子View的dispatchTouchEvent方法返回為true時(shí),則找到了新的TouchTarget毙石,并將其添加到TouchTarget形成的鏈表中廉沮。
  4. 遍歷TouchTarget形成的鏈表,然后對(duì)鏈表里面的子View分別調(diào)用dispatchTouchEvent徐矩,最后將處理結(jié)果返回滞时。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市丧蘸,隨后出現(xiàn)的幾起案子漂洋,更是在濱河造成了極大的恐慌,老刑警劉巖力喷,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刽漂,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡弟孟,警方通過查閱死者的電腦和手機(jī)贝咙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拂募,“玉大人庭猩,你說我怎么就攤上這事〕轮ⅲ” “怎么了蔼水?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)录肯。 經(jīng)常有香客問我趴腋,道長(zhǎng),這世上最難降的妖魔是什么论咏? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任优炬,我火速辦了婚禮,結(jié)果婚禮上厅贪,老公的妹妹穿的比我還像新娘蠢护。我一直安慰自己,他們只是感情好养涮,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布葵硕。 她就那樣靜靜地躺著,像睡著了一般单寂。 火紅的嫁衣襯著肌膚如雪贬芥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天宣决,我揣著相機(jī)與錄音蘸劈,去河邊找鬼。 笑死尊沸,一個(gè)胖子當(dāng)著我的面吹牛威沫,可吹牛的內(nèi)容都是我干的贤惯。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼棒掠,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼孵构!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起烟很,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤颈墅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后雾袱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恤筛,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年芹橡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了毒坛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡林说,死狀恐怖煎殷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情腿箩,我是刑警寧澤豪直,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站珠移,受9級(jí)特大地震影響顶伞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜剑梳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望滑潘。 院中可真熱鬧垢乙,春花似錦、人聲如沸语卤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽粹舵。三九已至钮孵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間眼滤,已是汗流浹背巴席。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诅需,地道東北人漾唉。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓荧库,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親赵刑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子分衫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348