关于事件分发和滑动冲突

2021-01-26  本文已影响0人  浩仔_Boy

自己学习笔记,仅供自己参考,如有不对欢迎指正
事件分发,概括成一句话:
Activity-PhoneWindow-DecorView-ViewGroup-View,如果view不处理,则会将事件往上传递最终交给Activity处理掉。

事件由上往下分发流程:
事件由上往下传递主要是通过DispatchTouchEvent方法,如果当前节点是ViewGroup则会循环它的所有子View的DispachTouchEvent。如果View不消耗MotionEvent.ACTION_DOWN 事件(onTouchEvent 返回false),后续事件的分发过程中不会调用此 View 的 dispatchTouchEvent 方法。

事件传到到最下层,view的处理;
当事件传递到最下层view,如果其不消耗或者只消耗了 MotionEvent.ACTION_DOWN 事件,但是不消耗同一事件序列的后续事件,则后续事件中不会调用 View 父元素的 onTouchEvent 方法,而是调用 Activity 的 onTouchEvent 方法

滑动冲突的处理:
目前不管是ScrollView、ViewPager等看他源码都已经做了滑动冲突。
滑动冲突处理,两种方案

1.在外层拦截

主要是拦截onInterceptTouchEvent方法

public class OuterInterceptView extends View {

    private float startY;

    private float startX;

    // --- 记录是否正在拖拽的标记

    private boolean mHorScroDraging;

    private final int mTouchSlop = ViewConfiguration.get(this.getContext()).getScaledTouchSlop();



    @Override

    public boolean onInterceptTouchEvent(MotionEvent ev) {

        {

            // -- 不拦截横向滑动

            int action = ev.getAction();

            switch (action) {

                case MotionEvent.ACTION_DOWN:

                    // --- 记录手指按下的位置

                    startY = ev.getY();

                    startX = ev.getX();

                    // --- 初始化标记

                    mHorScroDraging = false;

                    break;

                case MotionEvent.ACTION_MOVE:

                    // --- 如果正在横向中,那么不拦截它的事件,直接 return false;

                    if (mHorScroDraging) {

                        return false;

                    }

                    // --- 获取当前手指位置

                    float endY = ev.getY();

                    float endX = ev.getX();

                    float distanceX = Math.abs(endX - startX);

                    float distanceY = Math.abs(endY - startY);

                    // --- 如果 X 轴位移大于 Y 轴位移,那么将事件交给 viewPager 处理。

                    if (distanceX > mTouchSlop && distanceX > distanceY) {

                        mHorScroDraging = true;

                        return false;

                    }

                    break;

                case MotionEvent.ACTION_UP:

                case MotionEvent.ACTION_CANCEL:

                    // --- 初始化标记

                    mHorScroDraging = false;

                    break;

            }

        }

        return super.onInterceptTouchEvent(ev);

    }

}

2.在内部拦截
一般是拦截DispacthTouchEvent的方法,拦截掉down事件,如果父View还需要重新获得事件的处理权限,则可以调用requestDisallowInterceptTouchEvent方法。

public class InnerInterceptView extends View {

    private float startY;

    private float startX;

    // --- 记录是否正在 Ver 拖拽的标记

    private boolean mVerScroDraging;

    private final int mTouchSlop = ViewConfiguration.get(this.getContext()).getScaledTouchSlop();



    @Override

    public boolean dispatchTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {

            case MotionEvent.ACTION_DOWN:

                getParent().requestDisallowInterceptTouchEvent(true);

                // --- 记录手指按下的位置

                startY = ev.getY();

                startX = ev.getX();

                // --- 初始化标记

                mVerScroDraging = false;

                break;

            case MotionEvent.ACTION_MOVE:

                // --- 如果正在 Ver 拽中,那么让父容器拦截

                if (mVerScroDraging) {

                    getParent().requestDisallowInterceptTouchEvent(false);

                    return false;

                }

                // --- 获取当前手指位置

                float endY = ev.getY();

                float endX = ev.getX();

                float distanceX = Math.abs(endX - startX);

                float distanceY = Math.abs(endY - startY);

                // --- 如果 Y 轴位移大于 X 轴位移,那么将事件交给父容器处理。

                if (distanceY > mTouchSlop && distanceY > distanceX) {

                    mVerScroDraging = true;

                    getParent().requestDisallowInterceptTouchEvent(false);

                    return false;

                }

                break;

            case MotionEvent.ACTION_UP:

            case MotionEvent.ACTION_CANCEL:

                // --- 初始化标记

                mVerScroDraging = false;

                break;

        }

        return super.dispatchTouchEvent(ev);

    }

}
上一篇下一篇

猜你喜欢

热点阅读