03-深度理解-Android事件分發(fā)機(jī)制

你確定你對(duì)Android事件分發(fā)機(jī)制了然于胸了嗎?如果能麻溜的回答出下面幾個(gè)問題窝剖,還請(qǐng)大佬繞道沃饶,如果不能,請(qǐng)聽我細(xì)細(xì)講解:

1.View事件分發(fā)機(jī)制的傳遞過程是石抡?onTouch檐嚣,onTouchEvent,onClick的執(zhí)行順序汁雷?

2.DOWN事件分發(fā)機(jī)制的傳遞過程净嘀?遇到過滑動(dòng)沖突嗎报咳?怎么解決的?

3.MOVE事件分發(fā)機(jī)制的傳遞過程挖藏?

4.事件分發(fā)機(jī)制流程及優(yōu)缺點(diǎn)?

1. View事件分發(fā)機(jī)制的傳遞過程

1.1 View#dispatchTouchEvent:onTouch

public boolean dispatchTouchEvent(MotionEvent event) {

    // 事件消費(fèi)默認(rèn)返回false

    boolean result = false;

    // 觸摸事件安全過濾

    if (onFilterTouchEventForSecurity(event)) {

        // 判斷有沒有注冊(cè)onTouchListener暑刃,onTouch事件是否被消費(fèi)

        // 如果事件被onTouch消費(fèi)就不會(huì)繼續(xù)往下執(zhí)行;

        // 如果沒有被消費(fèi)膜眠,繼續(xù)執(zhí)行onTouchEvent方法岩臣。

        ListenerInfo li = mListenerInfo;

        if (li != null && li.mOnTouchListener != null

                && (mViewFlags & ENABLED_MASK) == ENABLED

                && li.mOnTouchListener.onTouch(this, event)) {

            result = true;

        }

        // 如果onTouchEvent事件被消費(fèi),則事件被消費(fèi)宵膨;

        // 如果onTouchEvent事件沒有被消費(fèi)架谎,那么事件依然會(huì)繼續(xù)往下傳遞。

        if (!result && onTouchEvent(event)) {

            result = true;

        }

    }

    return result;

}

1.2 View#onTouchEvent:onTouchEvent

public boolean onTouchEvent(MotionEvent event) {

    // 判斷是否注冊(cè)點(diǎn)擊事件

    final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE

            || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)

            || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;

    // 有點(diǎn)擊事件判斷action

    if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {

        switch (action) {

            case MotionEvent.ACTION_UP:

                // ACTION_UP事件觸發(fā)時(shí)辟躏,執(zhí)行performClick方法谷扣。

                performClick();

                break;

            case MotionEvent.ACTION_DOWN:

                break;

            case MotionEvent.ACTION_CANCEL:

                break;

            case MotionEvent.ACTION_MOVE:

                break;

        }

        return true;

    }

    return false;

}

1.3 View#performClick:onClick

public boolean performClick() {

    final boolean result;

    final ListenerInfo li = mListenerInfo;

    // 如果設(shè)置了onClickListener,就會(huì)執(zhí)行onClick方法捎琐,事件就會(huì)被消費(fèi)会涎。

    if (li != null && li.mOnClickListener != null) {

        playSoundEffect(SoundEffectConstants.CLICK);

        li.mOnClickListener.onClick(this);

        result = true;

    } else {

        result = false;

    }

    return result;

}

小貼士:

View沒有onInterceptTouchEvent方法,當(dāng)有點(diǎn)擊事件傳遞給它時(shí)瑞凑,就會(huì)執(zhí)行onTouchEvent方法末秃。

onTouchEvent方法:默認(rèn)消耗事件,但是如果View不可點(diǎn)擊就不會(huì)消耗事件籽御。

onClick事件會(huì)發(fā)生的前提:當(dāng)前View可點(diǎn)擊练慕,并且收到了down和up事件。

方法執(zhí)行順序:onTouch-onTouchEvent-onClick

思考:

一個(gè)需求:onTouch返回true要執(zhí)行onClick技掏。

解決辦法:在onTouch方法里ACTION_DOWN里加v.performClick();

場景:上層popupwindow擋住了下層view的點(diǎn)擊事件

上層popupwindow設(shè)置isTouchable=false

2.DOWN事件分發(fā)機(jī)制的傳遞過程:

2.1 Activity#dispatchTouchEvent:

當(dāng)我們點(diǎn)擊屏幕時(shí)铃将,觸發(fā)MotionEvent.ACTION_DOWN事件,此時(shí)屏幕處于Activity界面哑梳,Activity#dispatchTouchEvent方法進(jìn)行事件分發(fā):


public boolean dispatchTouchEvent(MotionEvent ev) {

    if (ev.getAction() == MotionEvent.ACTION_DOWN) {

        // 執(zhí)行和用戶交互的操作

        // 例如聰明的管理狀態(tài)欄通知麸塞,幫助activity在正確的時(shí)間取消通知

        onUserInteraction();

    }

    // 將事件傳遞給Window,Window#superDispatchTouchEvent進(jìn)行事件分發(fā)

    if (getWindow().superDispatchTouchEvent(ev)) {

        // Window消費(fèi)了該事件涧衙,直接return退出該方法

        return true;

    }

4

    // Window沒有消費(fèi)該事件哪工,繼續(xù)由Activity#onTouchEvent方法來處理

    return onTouchEvent(ev);

}

小貼士:

return的用法:

結(jié)束該方法,繼續(xù)執(zhí)行方法后面的語句弧哎。

2.2 Window#superDispatchTouchEvent:

public abstract boolean superDispatchTouchEvent(MotionEvent event);

Window類:抽象類雁比,superDispatchTouchEvent是抽象方法。

看Window類的介紹撤嫩,這個(gè)抽象類的唯一存在實(shí)現(xiàn)是PhoneWindow偎捎。

雙擊shift,搜索PhoneWindow類。

PhoneWindow#superDispatchTouchEvent:


@Override

public boolean superDispatchTouchEvent(MotionEvent event) {

    // PhoneWindow將事件傳遞給了DecorView

    return mDecor.superDispatchTouchEvent(event);

}

2.3 DecorView#superDispatchTouchEvent:

public boolean superDispatchTouchEvent(MotionEvent event) {

    // DecorView將事件傳遞給了ViewGroup

    return super.dispatchTouchEvent(event);

}

2.4 ViewGroup#dispatchTouchEvent:

@Override

// 事件分發(fā):dispatchTouchEvent

public boolean dispatchTouchEvent(MotionEvent ev) {

    boolean handled = false;

    if (onFilterTouchEventForSecurity(ev)) {

        // 注釋1

        // 初始化的原因:一個(gè)完整的事件序列是以DOWN開始茴她,以UP結(jié)束的寻拂。

        // 如果是DOWN事件,說明這是一個(gè)新的事件序列丈牢,所以需要初始化之前的狀態(tài)祭钉。

        if (actionMasked == MotionEvent.ACTION_DOWN) {

            // 清除觸摸目標(biāo)

            cancelAndClearTouchTargets(ev);

            // 重置觸摸狀態(tài)

            // mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT代碼意思是:將FLAG_DISALLOW_INTERCEPT標(biāo)志位設(shè)置為false。  

            resetTouchState();

        }

        // 注釋2

        final boolean intercepted;

        if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {

            // 因?yàn)槌跏蓟号妫栽撝禐閒alse

            final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;

            if (!disallowIntercept) {

                // 事件攔截:onInterceptTouchEvent

                // onInterceptTouchEvent返回true慌核,intercepted為true;

                // onInterceptTouchEvent返回false申尼,intercepted為false垮卓。

                intercepted = onInterceptTouchEvent(ev);

            } else {

                intercepted = false;

            }

        } else {

            intercepted = true;

        }

       // 注釋3

        final boolean canceled = resetCancelNextUpFlag(this) || actionMasked == MotionEvent.ACTION_CANCEL;

        // 注釋4

        TouchTarget newTouchTarget = null;

        if (!canceled && !intercepted) {

            if (actionMasked == MotionEvent.ACTION_DOWN

                    || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)

                    || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {

                final int childrenCount = mChildrenCount;

                if (newTouchTarget == null && childrenCount != 0) {

                    final ArrayList<View> preorderedList = buildTouchDispatchChildList();

                    for (int i = childrenCount - 1; i >= 0; i--) {

                        // 注釋5

                        final int childIndex = getAndVerifyPreorderedIndex(

                                childrenCount, i, customOrder);

                        final View child = getAndVerifyPreorderedView(

                                preorderedList, children, childIndex);

                        // 注釋6

                        if (!canViewReceivePointerEvents(child)

                                || !isTransformedTouchPointInView(x, y, child, null)) {

                            ev.setTargetAccessibilityFocus(false);

                            continue;

                        }

                        // 注釋7

                        newTouchTarget = getTouchTarget(child);

                        if (newTouchTarget != null) {

                            newTouchTarget.pointerIdBits |= idBitsToAssign;

                            break;

                        }

                        // 注釋8

                        resetCancelNextUpFlag(child);

                        if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {

                            if (preorderedList != null) {

                                for (int j = 0; j < childrenCount; j++) {

                                    if (children[childIndex] == mChildren[j]) {

                                        mLastTouchDownIndex = j;

                                        break;

                                    }

                                }

                            } else {

                                mLastTouchDownIndex = childIndex;

                            }

                            newTouchTarget = addTouchTarget(child, idBitsToAssign);

                            alreadyDispatchedToNewTouchTarget = true;

                            break;

                        }

                        ev.setTargetAccessibilityFocus(false);

                    }

                    if (preorderedList != null) preorderedList.clear();

                }

                if (newTouchTarget == null && mFirstTouchTarget != null) {

                    newTouchTarget = mFirstTouchTarget;

                    while (newTouchTarget.next != null) {

                        newTouchTarget = newTouchTarget.next;

                    }

                    newTouchTarget.pointerIdBits |= idBitsToAssign;

                }

            }

        }

        // 注釋9:

        if (mFirstTouchTarget == null) {

            handled = dispatchTransformedTouchEvent(ev, canceled, null,

                    TouchTarget.ALL_POINTER_IDS);

        } else {

            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;

            }

        }

        // 注釋10

        if (canceled

                || actionMasked == MotionEvent.ACTION_UP

                || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {

            resetTouchState();

        } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {

            final int actionIndex = ev.getActionIndex();

            final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);

            removePointersFromTouchTargets(idBitsToRemove);

        }

    }

    return handled;

}

Down事件:

注釋1:見代碼。

注釋2:

當(dāng)onInterceptTouchEvent返回true师幕,intercepted為true粟按,執(zhí)行注釋9。

mFirstTouchTarget為空霹粥,沒有進(jìn)行任何賦值钾怔,執(zhí)行dispatchTransformedTouchEvent方法。

dispatchTransformedTouchEvent:

canceled值:看注釋3#resetCancelNextUpFlag默認(rèn)為false蒙挑,且沒有執(zhí)行ACTION_CANCEL事件,所以值為false愚臀。


private static boolean resetCancelNextUpFlag(@NonNull View view) {

    // 如果if條件boolean類型為true忆蚀,條件置為false,該方法返回true

    if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {

        view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;

        return true;

    }

    // 該方法默認(rèn)返回false

    return false;

}

dispatchTransformedTouchEvent:cancel為false姑裂,child為null馋袜,執(zhí)行注釋2:


private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,

                                              View child, int desiredPointerIdBits) {

    final boolean handled;

    final int oldAction = event.getAction();

    // 注釋1

    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;

    }

    // 注釋2

    if (child == null) {

        // 執(zhí)行View#dispatchTouchEvent

        // super關(guān)鍵字:用來調(diào)用超類里的方法,ViewGroup繼承View舶斧。

        // 事件交給父容器來處理欣鳖。

        handled = super.dispatchTouchEvent(transformedEvent);

    } else {

        handled = child.dispatchTouchEvent(transformedEvent);

    }

    return handled;

}

當(dāng)onInterceptTouchEvent返回false,intercepted為false茴厉,假設(shè)canceled依然為false泽台,執(zhí)行注釋4。

執(zhí)行DOWN事件矾缓,newTouchTarget為空怀酷,mChildrenCount為ViewGroup中所有子View的數(shù)量不為0,執(zhí)行buildTouchDispatchChildList方法:


public ArrayList<View> buildTouchDispatchChildList() {

    // 對(duì)事件進(jìn)行排序

    return buildOrderedChildList();

}

buildOrderedChildList:將子視圖從ViewGroup到View(比如Button)從前往后依次有序添加到list集合中嗜闻,Z軸不斷增大蜕依。


ArrayList<View> buildOrderedChildList() {

    if (mPreSortedChildren == null) {

        mPreSortedChildren = new ArrayList<>(childrenCount);

    } else {

        mPreSortedChildren.clear();

        mPreSortedChildren.ensureCapacity(childrenCount);

    }

    for (int i = 0; i < childrenCount; i++) {

        final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);

        final View nextChild = mChildren[childIndex];

        final float currentZ = nextChild.getZ();

        int insertIndex = i;

        while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {

            insertIndex--;

        }

        mPreSortedChildren.add(insertIndex, nextChild);

    }

    return mPreSortedChildren;

}

回到注釋4:執(zhí)行for循環(huán)。

注釋5:從后往前第一個(gè)得到的View為Button。

注釋6:判斷View是否能收到點(diǎn)擊事件和點(diǎn)是否在它的坐標(biāo)里样眠。如果不能收到點(diǎn)擊事件或者不在坐標(biāo)里友瘤,繼續(xù)。

注釋7:getTouchTarget為空值檐束,執(zhí)行注釋8辫秧。

注釋8:

執(zhí)行dispatchTransformedTouchEvent方法,child不為空厢塘,執(zhí)行child#dispatchTouchEvent方法即View#dispatchTouchEvent方法茶没。即Button在處理事件。如果Button處理了事件晚碾,執(zhí)行注釋8的if里的內(nèi)容抓半。先拿到所有點(diǎn)擊事件的索引,然后用addTouchTarget方法將child賦值給mFirstTouchTarget格嘁,newTouchTarget為mFirstTouchTarget笛求,alreadyDispatchedToNewTouchTarget賦值為true。最后執(zhí)行break退出整個(gè)for循環(huán)糕簿。

注意:

如果注釋8的View沒有把事件消費(fèi)掉探入,那么剩余的Activity,Window懂诗,ViewGroup就會(huì)一直調(diào)用dispatchTransformTouchEvent處理事件直到把事件消費(fèi)為止蜂嗽。只要子View處理了事件,父View就再也不會(huì)接收到事件殃恒。

注釋9:

mFirstTouchTarget不為空植旧,target.next為空,handled為true离唐。

小貼士:

二進(jìn)制和按位操作符:& | ~

break:退出for循環(huán)病附。

2.5 ViewGroup#requestDisallowInterceptedTouchEvent:

定義:子View通過調(diào)用父View的requestDisallowInterceptTouchEvent方法來要求父View不攔截事件。

即:子View調(diào)用getParent().requestDisallowInterceptTouchEvent();

requestDisallowInterceptTouchEvent傳的值true亥鬓,disallowIntercept為true完沪。

當(dāng)為DOWN事件時(shí),ViewGroup#dispatchTouchEvent中注釋2處intercepted為false嵌戈,會(huì)執(zhí)行注釋4覆积,向子View傳遞。


@Override

public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {

        return;

    }

    if (disallowIntercept) {

        mGroupFlags |= FLAG_DISALLOW_INTERCEPT;

    } else {

        mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;

    }

    if (mParent != null) {

        mParent.requestDisallowInterceptTouchEvent(disallowIntercept);

    }

}

標(biāo)志位FLAG_DISALLOW_INTERCEPT的作用:

要求父View不攔截事件熟呛,向子View傳遞技健。

DOWN事件除外。因?yàn)槿绻茿CTION_DOWN事件惰拱,每次都會(huì)在注釋1處重置手勢(shì)狀態(tài)雌贱。

小結(jié):

DOWN事件的流程:

事件分發(fā)從父容器向子容器分發(fā)啊送。

事件分發(fā):dispatchTouchEvent

事件攔截:onInterceptTouchEvent。

為true不執(zhí)行注釋4欣孤,事件由父容器處理馋没;

為false執(zhí)行注釋4,向子View傳遞降传,發(fā)生到ViewGroup時(shí)篷朵,先問Button處不處理該事件,不處理就交給ViewGroup婆排,再根據(jù)for循環(huán)一層一層向上處理声旺。

ViewGroup想要攔截事件,可以重寫onInterceptTouchEvent方法返回true段只。

事件排序:buildTouchDispatchChildList腮猖,是為了從下往上排序處理。

事件處理:dispatchTransformedTouchEvent

事件消費(fèi):onTouchEvent

流程圖:

[圖片上傳失敗...(image-39be25-1692928698844)])

問題:

父View#onInterceptedTouchEvent設(shè)置為true赞枕,

DOWN事件requestDisallowInterceptedTouchEvent為true不起作用澈缺,還是會(huì)被父View攔截。

原因:

DOWN事件會(huì)在注釋1處進(jìn)行初始化炕婶,清除狀態(tài)姐赡,導(dǎo)致disallowIntercept為false執(zhí)行onInterceptTouchEvent方法為true被父View攔截。

解決:(重點(diǎn))

父View#onInterceptedTouchEvent:

當(dāng)點(diǎn)擊事件為ACTION_DOWN時(shí)柠掂,return false项滑,向子View傳遞。

如果onInterceptedTouchEvent是重寫的方法涯贞,還要寫方法super.onInterceptTouchEvent枪狂。

3.MOVE事件分發(fā)機(jī)制的傳遞過程:

執(zhí)行完DOWN事件就開始執(zhí)行MOVE事件。

3.1 ViewGroup#dispatchTouchEvent:

@Override

public boolean dispatchTouchEvent(MotionEvent ev) {

    boolean handled = false;

    if (onFilterTouchEventForSecurity(ev)) {

        // 注釋1:不執(zhí)行

        if (actionMasked == MotionEvent.ACTION_DOWN) {

            cancelAndClearTouchTargets(ev);

            resetTouchState();

        }

        // 注釋2:if 語句第二個(gè)條件mFirstTouchTarget不為空滿足

        final boolean intercepted;

        if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {

            final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;

            if (!disallowIntercept) {

                // 事件攔截:onInterceptTouchEvent

                intercepted = onInterceptTouchEvent(ev);

            } else {

                intercepted = false;

            }

        } else {

            intercepted = true;

        }

       // 注釋3

        final boolean canceled = resetCancelNextUpFlag(this) || actionMasked == MotionEvent.ACTION_CANCEL;

        // 注釋4

        TouchTarget newTouchTarget = null;

        // 第一個(gè) if 語句

        if (!canceled && !intercepted) {

            // 第二個(gè) if 語句

            if (actionMasked == MotionEvent.ACTION_DOWN

                    || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)

                    || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {

                final int childrenCount = mChildrenCount;

                if (newTouchTarget == null && childrenCount != 0) {

                    final ArrayList<View> preorderedList = buildTouchDispatchChildList();

                    for (int i = childrenCount - 1; i >= 0; i--) {

                        // 注釋5

                        final int childIndex = getAndVerifyPreorderedIndex(

                                childrenCount, i, customOrder);

                        final View child = getAndVerifyPreorderedView(

                                preorderedList, children, childIndex);

                        // 注釋6

                        if (!canViewReceivePointerEvents(child)

                                || !isTransformedTouchPointInView(x, y, child, null)) {

                            ev.setTargetAccessibilityFocus(false);

                            continue;

                        }

                        // 注釋7

                        newTouchTarget = getTouchTarget(child);

                        if (newTouchTarget != null) {

                            newTouchTarget.pointerIdBits |= idBitsToAssign;

                            break;

                        }

                        // 注釋8

                        resetCancelNextUpFlag(child);

                        if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {

                            if (preorderedList != null) {

                                for (int j = 0; j < childrenCount; j++) {

                                    if (children[childIndex] == mChildren[j]) {

                                        mLastTouchDownIndex = j;

                                        break;

                                    }

                                }

                            } else {

                                mLastTouchDownIndex = childIndex;

                            }

                            newTouchTarget = addTouchTarget(child, idBitsToAssign);

                            alreadyDispatchedToNewTouchTarget = true;

                            break;

                        }

                        ev.setTargetAccessibilityFocus(false);

                    }

                    if (preorderedList != null)

                        preorderedList.clear();

                }

                if (newTouchTarget == null && mFirstTouchTarget != null) {

                    newTouchTarget = mFirstTouchTarget;

                    while (newTouchTarget.next != null) {

                        newTouchTarget = newTouchTarget.next;

                    }

                    newTouchTarget.pointerIdBits |= idBitsToAssign;

                }

            }

        }

        // 注釋9:

        // 第一個(gè) if-else 語句

        if (mFirstTouchTarget == null) {

            handled = dispatchTransformedTouchEvent(ev, canceled, null,

                    TouchTarget.ALL_POINTER_IDS);

        } else {

            TouchTarget predecessor = null;

            TouchTarget target = mFirstTouchTarget;

            while (target != null) {

                final TouchTarget next = target.next;

                // 第二個(gè) if-else 語句

                if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {

                    handled = true;

                } else {

                    final boolean cancelChild = resetCancelNextUpFlag(target.child)

                            || intercepted;

// 第三個(gè) if 語句

                    if (dispatchTransformedTouchEvent(ev, cancelChild,

                            target.child, target.pointerIdBits)) {

                        handled = true;

                    }

// 第四個(gè) if 語句

                    if (cancelChild) {

                        if (predecessor == null) {

                            mFirstTouchTarget = next;

                        } else {

                            predecessor.next = next;

                        }

                        target.recycle();

                        target = next;

                        continue;

                    }

                }

                predecessor = target;

                target = next;

            }

        }

        // 注釋10

        if (canceled

                || actionMasked == MotionEvent.ACTION_UP

                || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {

            resetTouchState();

        } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {

            final int actionIndex = ev.getActionIndex();

            final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);

            removePointersFromTouchTargets(idBitsToRemove);

        }

    }

    return handled;

}

默認(rèn):

注釋2:onInterceptTouchEvent默認(rèn)返回false肩狂,執(zhí)行注釋4。

注釋4:第一個(gè) if 語句滿足姥饰,第二個(gè) if 語句 不滿足傻谁,執(zhí)行注釋9。

注釋9:

第一個(gè) if-else 語句列粪,mFirstTouchTarget是全局屬性审磁,在DOWN事件后不為空,執(zhí)行else岂座。

第二個(gè) if-else 語句态蒂,newTouchTarget是局部屬性,沒有執(zhí)行注釋4里的語句费什,所以為空钾恢,執(zhí)行else。

第三個(gè) if 語句,執(zhí)行dispatchTransformedTouchEvent方法瘩蚪,cancel為false泉懦,child不為空,執(zhí)行方法里注釋2的else語句即child.dispatchTouchEvent方法疹瘦。

第一次MOVE崩哩,父View攔截子View:

注釋2:假設(shè)onInterceptTouchEvent返回true,不執(zhí)行注釋4言沐,執(zhí)行注釋9邓嘹。

注釋9:

第一個(gè) if-else 語句,同上险胰。

第二個(gè) if-else 語句汹押,同上。

第三個(gè) if 語句:

  • 執(zhí)行dispatchTransformedTouchEvent方法鸯乃,cancel為true鲸阻,child不為空,執(zhí)行方法里的注釋1缨睡。

  • MotionEvent事件設(shè)置為了ACTION_CANCEL鸟悴,調(diào)用child.dispatchTouchEvent方法,但是最后事件還是oldAction即MOVE事件奖年。

重點(diǎn):此處child取消了事件细诸。

第四個(gè) if 語句:將mFirstTouchTarget置為了空。

第二次MOVE:

MOVE事件會(huì)多次觸發(fā)陋守,再從執(zhí)行MOVE事件:

注釋2:執(zhí)行 else 語句 intercepted = true 部分震贵。

注釋4:不執(zhí)行

注釋9:執(zhí)行第一個(gè) if-else 語句的 if 語句,即 dispatchTransformedTouchEvent方法水评,cancel為false猩系,child為空,執(zhí)行方法里注釋2的else語句super.dispatchTouchEvent即父View它自己的dispatchTouchEvent中燥。

流程圖:

[圖片上傳失敗...(image-f7701e-1692928698844)])

MotionEvent中的四個(gè)事件:

ACTION_DOWN:手指初次接觸到屏幕時(shí)觸發(fā)

ACTION_MOVE:手指在屏幕上滑動(dòng)時(shí)觸發(fā)寇甸,會(huì)多次觸發(fā)

ACTION_UP:手指離開屏幕時(shí)觸發(fā)

ACTION_CANCEL:事件被上層攔截時(shí)觸發(fā)

4.事件分發(fā)機(jī)制流程及優(yōu)缺點(diǎn):

事件分發(fā)機(jī)制其實(shí)是一個(gè)責(zé)任鏈模式,上級(jí)交給下級(jí),下級(jí)完成不了再交給上級(jí)。但是這樣做的缺點(diǎn)是層級(jí)太多同云,不夠扁平化。

[圖片上傳失敗...(image-5d1707-1692928698844)])

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绽淘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子闹伪,更是在濱河造成了極大的恐慌沪铭,老刑警劉巖壮池,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異伦意,居然都是意外死亡火窒,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門驮肉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來熏矿,“玉大人,你說我怎么就攤上這事离钝∑北啵” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵卵渴,是天一觀的道長慧域。 經(jīng)常有香客問我,道長浪读,這世上最難降的妖魔是什么昔榴? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮碘橘,結(jié)果婚禮上互订,老公的妹妹穿的比我還像新娘。我一直安慰自己痘拆,他們只是感情好仰禽,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著纺蛆,像睡著了一般吐葵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上桥氏,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天温峭,我揣著相機(jī)與錄音,去河邊找鬼字支。 笑死凤藏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的祥款。 我是一名探鬼主播清笨,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼月杉,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼刃跛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起苛萎,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤桨昙,失蹤者是張志新(化名)和其女友劉穎检号,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛙酪,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡齐苛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了桂塞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凹蜂。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖阁危,靈堂內(nèi)的尸體忽然破棺而出玛痊,到底是詐尸還是另有隱情,我是刑警寧澤狂打,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布擂煞,位于F島的核電站,受9級(jí)特大地震影響趴乡,放射性物質(zhì)發(fā)生泄漏对省。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一晾捏、第九天 我趴在偏房一處隱蔽的房頂上張望蒿涎。 院中可真熱鬧,春花似錦粟瞬、人聲如沸同仆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽俗批。三九已至,卻和暖如春市怎,著一層夾襖步出監(jiān)牢的瞬間岁忘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來泰國打工区匠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留干像,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓驰弄,卻偏偏與公主長得像麻汰,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子戚篙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

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