美文网首页
滑动冲突处理

滑动冲突处理

作者: 水清波 | 来源:发表于2019-08-14 11:31 被阅读0次

    分2种:内部拦截和外部拦截

    外部拦截

    viewgroup用onInterceptTouchEvent处理,对需要的事件返回true拦截掉,子节点再也没有机会接触到事件,所有事件自己的ontouch处理。

    内部拦截

    子view通过requestDisallowInterceptTouchEvent可以让父view不再拦截事件
    前提是down事件发生的时候viewgroup不能拦截,如果拦截了,view根本就没机会收到事件。
    如果down事件到达了子view,viewgroup拦截move事件等,这种情况下,子view用requestDisallowInterceptTouchEvent优先在viewgroup的拦截前不允许拦截,就把move事件还是发送到子view里去。

    以viewgroup解释
    起点肯定是dispatchTouchEvent

                final int action = ev.getAction();
                final int actionMasked = action & MotionEvent.ACTION_MASK;
                if (actionMasked == MotionEvent.ACTION_DOWN) {
                    cancelAndClearTouchTargets(ev);
                    resetTouchState();
                }
    //清除掉内部的TouchTarget链表,如果TouchTarget内有节点,发送当前事件给他们然后清理
    
    //如果是ACTION_DOWN,做拦截判断,先用requestparentIntercept的标识判断
    //后自己的onInterceptTouchEvent判断
    //或者mFirstTouchTarget有值,说明自己在处理,这2种情况说明拦截了
                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;
                }
    

    down事件先清除了mFirstTouchTarget,所以down进入后后续的进入,都会判断是否被子类要求不拦截,子类要求不拦截后,才能走自己的onInterceptTouchEvent。
    后续判断是否做了取消动作,
    如果不取消不拦截一个分支:final ArrayList<View> preorderedList = buildTouchDispatchChildList();建立子child表用Z轴排序
    dispatchTransformedTouchEvent去子child分发
    如果分发成功,使用addTouchTarget加入一个TouchTarget节点

    后续使用mFirstTouchTarget来判断,mFirstTouchTarget空说明没有加入到节点,说明没有child处理,吧自己当作普通view调用dispatchTransformedTouchEvent,由于内部没有child调用view.dispatchTouchEvent最终去触发ontouch了。
    dispatchTransformedTouchEvent的结果被作为viewgroup.dispatchTouchEvent返回
    这一系列就循环了。

    TouchTarget是一个类似链表结构的有下级引用的内部静态类

    private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
            final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
            target.next = mFirstTouchTarget;
            mFirstTouchTarget = target;
            return target;
        }
    

    addTouchTarget指出 mFirstTouchTarget是TouchTarget链表的表头,操作都在表头,就是一个栈

    分发事件给子节点,没有子节点把自己当一个viwe处理,否则给子节点处理

    private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
                View child, int desiredPointerIdBits) {
    if (child == null) {
                handled = super.dispatchTouchEvent(transformedEvent);
            } else {
                final float offsetX = mScrollX - child.mLeft;
                final float offsetY = mScrollY - child.mTop;
                transformedEvent.offsetLocation(offsetX, offsetY);
                if (! child.hasIdentityMatrix()) {
                    transformedEvent.transform(child.getInverseMatrix());
                }
    
                handled = child.dispatchTouchEvent(transformedEvent);
            }
    }
    

    相关文章

      网友评论

          本文标题:滑动冲突处理

          本文链接:https://www.haomeiwen.com/subject/ojshdctx.html