android ViewGroup 事件分發(fā)

1、ViewGroup跟上一節(jié)View一樣先看各種情況下的日志然后在根據(jù)日志情況來分析源碼

1.1 在默認(rèn)都存在的情況下日志

09-12 06:46:19.390 19085-19085/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 0
09-12 06:46:19.390 19085-19085/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 0
09-12 06:46:19.390 19085-19085/com.example.chao.viewontouch I/Tag: view -> dispatchTouchEvent -> 0
09-12 06:46:19.390 19085-19085/com.example.chao.viewontouch I/Tag: view -> onTouch
09-12 06:46:19.390 19085-19085/com.example.chao.viewontouch I/Tag: view -> onTouchEvent -> 0
09-12 06:46:19.410 19085-19085/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 2
09-12 06:46:19.410 19085-19085/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 2
09-12 06:46:19.410 19085-19085/com.example.chao.viewontouch I/Tag: view -> dispatchTouchEvent -> 2
09-12 06:46:19.410 19085-19085/com.example.chao.viewontouch I/Tag: view -> onTouch
09-12 06:46:19.410 19085-19085/com.example.chao.viewontouch I/Tag: view -> onTouchEvent -> 2
09-12 06:46:19.557 19085-19085/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 1
09-12 06:46:19.557 19085-19085/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 1
09-12 06:46:19.557 19085-19085/com.example.chao.viewontouch I/Tag: view -> dispatchTouchEvent -> 1
09-12 06:46:19.557 19085-19085/com.example.chao.viewontouch I/Tag: view -> onTouch
09-12 06:46:19.558 19085-19085/com.example.chao.viewontouch I/Tag: view -> onTouchEvent -> 1
09-12 06:46:19.561 19085-19085/com.example.chao.viewontouch I/Tag: view -> onClick

1.2 這次是取消onClickListener情況下日志 取消了onClickListener 等于沒有消費事件

09-12 06:44:39.744 17254-17254/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 0
09-12 06:44:39.744 17254-17254/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 0
09-12 06:44:39.744 17254-17254/com.example.chao.viewontouch I/Tag: view -> dispatchTouchEvent -> 0
09-12 06:44:39.744 17254-17254/com.example.chao.viewontouch I/Tag: view -> onTouch
09-12 06:44:39.744 17254-17254/com.example.chao.viewontouch I/Tag: view -> onTouchEvent -> 0
09-12 06:44:39.744 17254-17254/com.example.chao.viewontouch I/Tag: ViewGroup -> onTouchEvent ->0

1.3 在view中的onTouchEvent 返回值為true

09-12 06:45:40.509 18253-18253/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 0
09-12 06:45:40.509 18253-18253/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 0
09-12 06:45:40.509 18253-18253/com.example.chao.viewontouch I/Tag: view -> dispatchTouchEvent -> 0
09-12 06:45:40.509 18253-18253/com.example.chao.viewontouch I/Tag: view -> onTouch
09-12 06:45:40.509 18253-18253/com.example.chao.viewontouch I/Tag: view -> onTouchEvent -> 0
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 2
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 2
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: view -> dispatchTouchEvent -> 2
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: view -> onTouch
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: view -> onTouchEvent -> 2
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 1
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 1
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: view -> dispatchTouchEvent -> 1
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: view -> onTouch
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: view -> onTouchEvent -> 1

1.4 在ViewGroup中的onInterceptTouchEvent返回true

09-12 05:51:04.638 21669-21669/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 0
09-12 05:51:04.638 21669-21669/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 0
09-12 05:51:04.638 21669-21669/com.example.chao.viewontouch I/Tag: ViewGroup -> onTouchEvent ->0

接下來第二節(jié)來通過源碼解析為什么會出現(xiàn)這種情況

首先還是找到ViewGroup的dispatchTouchEvent(ev)

boolean handled = false dispatchTouchEvent 返回值

接下來看這段話 這段話就清除所有的狀態(tài) resetTouchState() mFirstTouchTarget 也是在里面置空 mFirstTouchTarget 下面會講到

if (actionMasked == MotionEvent.ACTION_DOWN) {
                // Throw away all previous state when starting a new touch gesture.
                // The framework may have dropped the up or cancel event for the previous gesture
                // due to an app switch, ANR, or some other state change.
                cancelAndClearTouchTargets(ev);
                resetTouchState();
    }

以下這段代碼比較重要 第一次按下的話 actionMasked == MotionEvent.ACTION_DOWN 這個肯定是down事件 所以一定會進入if判斷

final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; 這段話就是判斷子View有沒有請求父控件不攔截 也就是這段 getParent().requestDisallowInterceptTouchEvent(true);

這里我們也沒有調(diào)用這個方法 所以intercepted為false就是不攔截繼續(xù)往下走

            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;
            }

接下來這段代碼比較長 只取關(guān)鍵代碼newTouchTarget = addTouchTarget(child, idBitsToAssign); addTouchTarget 這段對mFirstTouchTarget 和 newTouchTarget賦值

if (actionMasked == MotionEvent.ACTION_DOWN
                        || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
                        || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
    ....
    .....
    if (newTouchTarget == null && childrenCount != 0) {
        ....
        ....
        
        newTouchTarget = addTouchTarget(child, idBitsToAssign);
        
    }
}

整個ViewGroup事件分發(fā)的核心就這這下面的代碼了

 // 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;
                }
 }

經(jīng)過上面的分析 我們知道 mFirstTouchTarget 是不為空 所以走else的代碼塊 我們看到 if (dispatchTransformedTouchEvent(ev, cancelChild,target.child, target.pointerIdBits))這里面

只看一部分

        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;
        }

如果說子 View 沒有一個地方返回 true ,只會進來一次只會響應(yīng) DOWN 事件,代表不需要消費該事件,如果你想響應(yīng) MOVE,UP 必須找個地方ture對于ViewGroup來講,如果你想攔截子 View 的 Touch 事件,可以覆寫 onInterceptTouchEvent 返回 true 即可 , 如果說 onInterceptTouchEvent 返回的是 true 會執(zhí)行該 ViewGroup 的 onTouchEvent 方法 , 如果子 View 沒有消費 touch 事件也會調(diào)用該 ViewGroup 的 onTouchEvent 方法

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

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