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

关于事件分发和滑动冲突

作者: 浩仔_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);

    }

}

相关文章

  • 关于事件分发和滑动冲突

    自己学习笔记,仅供自己参考,如有不对欢迎指正事件分发,概括成一句话:Activity-PhoneWindow-De...

  • Android View | View 的滑动冲突

    滑动冲突在实际项目中十分常见,解决滑动冲突的核心是结合事件的分发机制,了解事件的分发可参考这里。 常见的滑动冲突场...

  • Android ScrollView 嵌套RecyclerVie

    ScrollView 和RecyclerView都是滑动组件,因此存在滑动事件冲突问题,解决思路就是在事件分发函数...

  • android 事件分发以及滑动冲突

    android 事件分发以及滑动冲突 Android Activity 页面布局如下: view 的事件分发机制 ...

  • Android系统知识全览---View知识体系(2)---Vi

    View的事件体系 View的概念 View的事件 View的滑动事件 View事件分发机制 View的滑动冲突解...

  • Android View事件分发

    开发当中经常需要处理滑动冲突,而滑动冲突这种老大难的问题的理论基础就是事件分发机制 首先我们来认识下事件分发中3个...

  • Android 收藏

    图解 Android 事件分发机制 ViewPager,ScrollView 嵌套ViewPager滑动冲突解决

  • View的事件体系(下)

    目录 View的事件分发机制 View的滑动冲突 View的事件分发机制 点击事件的传递规则 View的点击事件的...

  • android事件分发

    事件分发在Android中非常重要,在滑动冲突,下拉刷新,嵌套滑动的时候都需要非常清楚事件分发的机制,才能写好对应...

  • Android应用开发三部曲 --- Touch事件分发

    1、前言 Android应用开发中,经常会遇到touch事件分发的问题,甚至还会遇到滑动冲突问题,如果解决滑动冲突...

网友评论

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

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