滑动冲突处理

2019-08-14  本文已影响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);
        }
}
上一篇下一篇

猜你喜欢

热点阅读