dispatchTouchEvent()源碼看事件分發(fā)機(jī)制

前言

通過(guò)對(duì)ViewGroup與View的dispatchTouchEvent()源碼簡(jiǎn)要分析看View的事件分發(fā)原理.

ViewGroup的dispatchTouchEvent()

局部變量handled代表是否處理,初始化為false.

1.檢測(cè)View是否安全.

onFilterTouchEventForSecurity(),主要是判斷View有沒(méi)有被遮蔽.如果不通過(guò)返回handled.通過(guò)走下一步.

2.重置mGroupFlags,清空touchTarget.

如果是ACTIONDOWN事件,
a.重置mGroupFlags使boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0為false.
b.
mFirstTouchTarget是單鏈表結(jié)構(gòu).在addTOuchTarget()的時(shí)候被賦值,新建一個(gè)Target,next節(jié)點(diǎn)賦值為mFirstTouchTarget,mFirstTouchTarget賦值為新的target.
概括來(lái)說(shuō)一旦有子View處理了事件序列中某一個(gè)事件,那么mFirstTouchTarget就不為空.
遍歷TouchTarget鏈表,釋放清空鏈表,最后mFirstTouchTarget賦值為空.

3.intercepted變量賦值,表示是否攔截.

判斷actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null,為false,intercepted賦值為true.走下一步.

false意味著,當(dāng)不是ACTION_DOWN事件,且mFirstTouchTarget為空(子View沒(méi)有處理事件序列中的任一事件).
所以子View不處理ACTION_DOWN或者攔截了ACTION_DOWN,子View將無(wú)法得到其他的事件

true判斷disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0,true,intercepted賦值為false.false,intercepted = onInterceptTouchEvent(ev).

4.判斷!canceled && !intercepted

canceled的分析//fixme

!canceled && !intercepted為true.遍歷子View,判斷子元素:1.是否可見(jiàn)或者在播放動(dòng)畫(huà)2.事件坐標(biāo)是否在子View的區(qū)域
如果1和2是true調(diào)用dispatchTransformedTouchEvent().dispatchTransformedTouchEvent()在View不為空的情況下就會(huì)調(diào)用子View的dispatchTouchEvent().子View處理了alreadyDispatchedToNewTouchTarget 賦值為true;mFirstTouchTarget賦值.

!canceled && !intercepted為flase.清空狀態(tài),給子View分發(fā)Cancle事件,Target鏈表清空,mFirstTarget賦值為null.
這里反應(yīng)出父View一旦攔截某個(gè)事件,事件序列中之后的事件都將interCepted設(shè)置為true,不會(huì)執(zhí)行onInterCepted()去判斷了.因?yàn)榈冢膊降膍FirstTarget為null.

開(kāi)始這里我是有疑問(wèn)的,外部攔截不是有move部分?jǐn)r截嗎,攔截了那么之后子View就沒(méi)反應(yīng)了?確認(rèn)下代碼,想了想,事件序列這個(gè)概念比較重要.move攔截了一次,那么mFirstTarget為null.就一直攔截了.

這里我又觀察到一個(gè)現(xiàn)象,我在測(cè)試外部攔截處理滑動(dòng)沖突的時(shí)候,move事件的攔截是有條件的,一開(kāi)始不攔截,在ontercepted()打印了幾次不攔截的日志.之后ontercepted()就沒(méi)有再執(zhí)行了.查看源碼只有改變mGroupFlags為false才會(huì)有這種現(xiàn)象.于是我去內(nèi)層的RecyclerView中查找是否調(diào)用requestDisallowInterceptTouchEvent()方法.發(fā)現(xiàn)在onTounchEvent()中就有調(diào)用,發(fā)現(xiàn)有滾動(dòng)消耗就調(diào)用requestDisallowInterceptTouchEvent()方法使得外層mGroupFlags判定結(jié)果是false.

5.handled賦值

判斷mFirstTouchTarget == null

true調(diào)用handled = dispatchTransformedTouchEvent(),執(zhí)行super.dispatchTouchEvent(event)即View的dispatchTouchEvent(event).View的dispatchTouchEvent之后分析.

false根據(jù)子View的處理情況將handled賦值.

View的dispatchTouchEvent()


        if (onFilterTouchEventForSecurity(event)) {
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                result = true;
            }
            //noinspection SimplifiableIfStatement
            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;
            }
        }

在判斷onFilterTouchEventForSecurity后,如果View可用且mOnTouchListener.onTouch(this, event))返回true,就返回true.否則
result = onTouchEvent().

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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