android 连续事件处理

场景:

手指点击屏幕之后,滑动一段距离然后抬起

事件:

ACTION_DOWN、ACTION_MOVE、…、ACTION_MOVE、ACTION_UP

先说结论:

  • 如果子 view 未消费上次事件,那么后续事件不会再传递给它(也不再调用 onInterceptTouchEvent 方法)
  • 如果子 view 消费了上次的事件,那么后续事件都会尝试着传递给它;后续事件会调用 onInterceptTouchEvent 方法
    (之所以说尝试是因为 onInterceptTouchEvent 方法仍然可以拦截)
  • dispatchTouchEvent 所有、每次事件发生都会走
  • 对于onInterceptTouchEvent,down 事件或上次事件被子 view 消费时才会走

伪代码

如下(对应源码:android.view.ViewGroup#dispatchTouchEvent()):

    final int action = ev.getAction();
        final int actionMasked = action & MotionEvent.ACTION_MASK;

        // Check for interception.
        final boolean intercepted;

        //idea:意为只有本次为 DOWN 事件,或者上次的事件被子 view 消费时,才会再看看是否需要调用(未修改 mGroupFlags 时) onInterceptTouchEvent
        if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
            //idea: 使用 requestDisallowInterceptTouchEvent 方法来处理滑动冲突就是利用了此行代码
            final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
            if (!disallowIntercept) {
                intercepted = onInterceptTouchEvent(ev);

                //idea: restore action in case it was changed,也就是防止篡改
                ev.setAction(action);
            } 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;
        }

        // Check for cancelation.
        final boolean canceled = resetCancelNextUpFlag(this)
                || actionMasked == MotionEvent.ACTION_CANCEL;



        //idea: 未取消掉且未被拦截时
        if (!canceled && !intercepted) {

            if (actionMasked == MotionEvent.ACTION_DOWN || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {

                final int childrenCount = mChildrenCount;
                if (childrenCount != 0) {

                    for (int i = childrenCount - 1; i >= 0; i--) {
                        final View child = ...;

                        //idea 将其传递给子 view
                        if (child.dispatchTouchEvent(ev)) {
                            //idea 子 view 说要处理此事件时,获取 child 对应的 TouchTarget
                            final TouchTarget tmpTarget = TouchTarget.obtain(child, pointerIdBits);
                            tmpTarget.next = mFirstTouchTarget;
                            //idea: 重点出现了
                            mFirstTouchTarget = tmpTarget;
                            break;
                        }
                    }
                }
            }
        }

        // Dispatch to touch targets.
        if (mFirstTouchTarget == null) {
            // No touch targets so treat this as an ordinary view.
        } else {
            // Dispatch to touch targets, excluding the new touch target if we already
            // dispatched to it.  Cancel touch targets if necessary.
        }

        // Update list of touch targets for pointer up or cancel, if needed.

猜你喜欢

转载自blog.csdn.net/lonewolf521125/article/details/78021472