国产一区二区精品-国产一区二区精品久-国产一区二区精品久久-国产一区二区精品久久91-免费毛片播放-免费毛片基地

千鋒教育-做有情懷、有良心、有品質的職業教育機構

手機站
千鋒教育

千鋒學習站 | 隨時隨地免費學

千鋒教育

掃一掃進入千鋒手機站

領取全套視頻
千鋒教育

關注千鋒學習站小程序
隨時隨地免費學習課程

當前位置:首頁  >  技術干貨  > ACTION_CANCEL到底何時觸發,滑出子View范圍會發生什么?

ACTION_CANCEL到底何時觸發,滑出子View范圍會發生什么?

來源:千鋒教育
發布人:xqq
時間: 2023-10-12 21:31:42 1697117502

一、ACTION_CANCEL在這些時候會觸發

1、父view攔截事件

首先要了解ViewGroup什么情況下會攔截事件,請看下面一段代碼:

@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) ...    boolean handled = false;    if (onFilterTouchEventForSecurity(ev))         final int action = ev.getAction();        final int actionMasked = action & MotionEvent.ACTION_MASK;...        // Check for interception.        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;                ...        ...

可以看出有兩個條件:

MotionEvent.ACTION_DOWN事件或者mFirstTouchTarget非空也就是有子view在處理事件子view沒有做攔截,也就是沒有調用ViewParent#requestDisallowInterceptTouchEvent(true)

如果滿足上面的兩個條件才會執行onInterceptTouchEvent(ev)。如果ViewGroup攔截了事件,則intercepted變量為true,接著往下看:

@Overridepublic boolean dispatchTouchEvent(MotionEvent ev)         boolean handled = false;    if (onFilterTouchEventForSecurity(ev))         ...        // Check for interception.        final boolean intercepted;        if (actionMasked == MotionEvent.ACTION_DOWN                || mFirstTouchTarget != null)             final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;            if (!disallowIntercept)                 // 當mFirstTouchTarget != null,也就是子view處理了事件                // 此時如果父ViewGroup攔截了事件,intercepted==true                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;                ...        // Dispatch to touch targets.        if (mFirstTouchTarget == null)             ...         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)                     ...                 else                     // 判斷一:此時cancelChild == true                    final boolean cancelChild = resetCancelNextUpFlag(target.child)                            || intercepted;// 判斷二:給child發送cancel事件                    if (dispatchTransformedTouchEvent(ev, cancelChild,                            target.child, target.pointerIdBits))                         handled = true;                                        ...                ...    return handled;

以上判斷一處cancelChild為true,然后進入判斷二中一看究竟:

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設置成ACTION_CANCEL        event.setAction(MotionEvent.ACTION_CANCEL);        if (child == null)             ...         else             // 分發給child            handled = child.dispatchTouchEvent(event);                event.setAction(oldAction);        return handled;

當參數cancel為ture時會將event設置為MotionEvent.ACTION_CANCEL,然后分發給child。

2、ACTION_DOWN初始化操作

首先請看一段代碼:

public boolean dispatchTouchEvent(MotionEvent ev)     boolean handled = false;    if (onFilterTouchEventForSecurity(ev))         final int action = ev.getAction();        final int actionMasked = action & MotionEvent.ACTION_MASK;        // Handle an initial down.        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.            // 取消并清除所有的Touch目標            cancelAndClearTouchTargets(ev);            resetTouchState();        ...        ...

系統可能會由于App切換、ANR等原因丟失了up,cancel事件。因此需要在ACTION_DOWN時丟棄掉所有前面的狀態,具體代碼如下:

private void cancelAndClearTouchTargets(MotionEvent event)     if (mFirstTouchTarget != null)         boolean syntheticEvent = false;        if (event == null)             final long now = SystemClock.uptimeMillis();            event = MotionEvent.obtain(now, now,                    MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);            event.setSource(InputDevice.SOURCE_TOUCHSCREEN);            syntheticEvent = true;                for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next)             resetCancelNextUpFlag(target.child);            // 分發事件同情況一            dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);                ...

PS:在dispatchDetachedFromWindow()中也會調用cancelAndClearTouchTargets()

3、在子View處理事件的過程中被從父View中移除時

請看下面這段代碼:

public void removeView(View view)     if (removeViewInternal(view))         requestLayout();        invalidate(true);    private boolean removeViewInternal(View view)     final int index = indexOfChild(view);    if (index >= 0)         removeViewInternal(index, view);        return true;        return false;private void removeViewInternal(int index, View view)     ...    cancelTouchTarget(view);...private void cancelTouchTarget(View view)     TouchTarget predecessor = null;    TouchTarget target = mFirstTouchTarget;    while (target != null)         final TouchTarget next = target.next;        if (target.child == view)             ...            // 創建ACTION_CANCEL事件            MotionEvent event = MotionEvent.obtain(now, now,                    MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);            event.setSource(InputDevice.SOURCE_TOUCHSCREEN);            分發給目標view            view.dispatchTouchEvent(event);            event.recycle();            return;                predecessor = target;        target = next;

4、子View被設置了PFLAG_CANCEL_NEXT_UP_EVENT標記時

請看下面這段代碼,在情況一種的兩個判斷處:

// 判斷一:此時cancelChild == truefinal boolean cancelChild = resetCancelNextUpFlag(target.child)|| intercepted;// 判斷二:給child發送cancel事件if (dispatchTransformedTouchEvent(ev, cancelChild,    target.child, target.pointerIdBits))     handled = true;

當?resetCancelNextUpFlag(target.child)?為true時同樣也會導致cancel,查看代碼:

/** * Indicates whether the view is temporarily detached. * * @hide */static final int PFLAG_CANCEL_NEXT_UP_EVENT        = 0x04000000;private static boolean resetCancelNextUpFlag(View view)     if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0)         view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;        return true;        return false;

二、滑出子View范圍會發生什么

通常來說,滑出子View范圍什么也不會發生。如果手指移出了子View之外,從而導致事件序列被取消,那么通常不會有太多事情發生。您的應用程序將會收到一個ACTION_CANCEL事件,但是由于事件已經被取消,您無法執行任何進一步的操作。如果您希望避免這種情況發生,您可以嘗試使用requestDisallowInterceptTouchEvent()方法來防止觸摸事件序列被攔截,或者重新設計您的UI以確保用戶不會意外地移動手指到View的范圍外。

延伸閱讀1:ACTION_CANCEL作用

我們知道如果某一個子View處理了Down事件,那么隨之而來的Move和Up事件也會交給它處理。但是交給它處理之前,父View還是可以攔截事件的,如果攔截了事件,那么子View就會收到一個Cancel事件,并且不會收到后續的Move和Up事件。

聲明:本站稿件版權均屬千鋒教育所有,未經許可不得擅自轉載。
10年以上業內強師集結,手把手帶你蛻變精英
請您保持通訊暢通,專屬學習老師24小時內將與您1V1溝通
免費領取
今日已有369人領取成功
劉同學 138****2860 剛剛成功領取
王同學 131****2015 剛剛成功領取
張同學 133****4652 剛剛成功領取
李同學 135****8607 剛剛成功領取
楊同學 132****5667 剛剛成功領取
岳同學 134****6652 剛剛成功領取
梁同學 157****2950 剛剛成功領取
劉同學 189****1015 剛剛成功領取
張同學 155****4678 剛剛成功領取
鄒同學 139****2907 剛剛成功領取
董同學 138****2867 剛剛成功領取
周同學 136****3602 剛剛成功領取
相關推薦HOT