美文网首页
关于事件分发和滑动冲突

关于事件分发和滑动冲突

作者: 浩仔_Boy | 来源:发表于2021-01-26 10:37 被阅读0次

    自己学习笔记,仅供自己参考,如有不对欢迎指正
    事件分发,概括成一句话:
    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);
    
        }
    
    }
    

    相关文章

      网友评论

          本文标题:关于事件分发和滑动冲突

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