Android事件分发机制(3)-处理滑动冲突

阅读本篇文章之前,建议先阅读Android 事件分发机制(1)-源码分析_z936689039的博客-CSDN博客

1.案例1

View的滑动冲突

这块得采用ViewGroup中发现ps小总结咯:

1.当ACTION_MOVE和ACTION_UP事件到来时,如果没有子元素处理事件(mFirstTouchTarget==null),则ViewGroup的onInterceptTouchEvent不会再被调用,而且同一序列中的其它事件都会默认交给它处理( intercepted=true),都由 ViewGroup 自行处理。
2.一旦子元素有调用这个requestDisallowInterceptTouchEvent(true) 方法,那么此 ViewGroup 将无法拦截除 DOWN 以外的其他事件。

1.1.外部拦截法:

顾名思义,就是直接对外部的ViewGroup进行拦截处理,这块处理的话就是采用1的方法,即直接重写onInterceptTouchEvent,然后子View处理剩余的事件,这块主要有以下几点:

1.父类不能拦截ACTION_DOWN,也就是说ACTION_DOWN的时候必须返回false,就是不拦截

2.父类在ACTION_MOVE的时候根据需求,判断是否拦截。

3.ACTION_UP事件建议返回false或者super.onInterceptTouchEvent,因为如果已经拦截的话,那么并不会调用onInterceptTouchEvent方法再次询问。如果不拦截,而且返回true,子View可能就无法触发onClick等相关事件。

实现:

 private boolean isIntercept;
    private boolean isSolve;//是否完成了拦截判断,如果决定拦截,那么同系列事件就不能设置为不拦截

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mPointGapF.x = ev.getX();
                mPointGapF.y = ev.getY();
                return false;//down的时候拦截后,就只能交给自己处理了

            case MotionEvent.ACTION_MOVE:
                if (!isSolve) {//是否已经决定拦截/不拦截?
                    isIntercept = (Math.abs(ev.getX() - mPointGapF.x) > Math.abs(ev.getY() - mPointGapF.y)*2);//如果是左右滑动,且水平角度小于30°,就拦截
                    isSolve = true;
                }
                return isIntercept;//如果是左右滑动,就拦截
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_MOVE:
                scrollBy((int) (mPointGapF.x - ev.getX()), 0);

                mPointGapF.x = ev.getX();
                mPointGapF.y = ev.getY();
                break;
        }
        return super.onTouchEvent(ev);
    }

子View : 和子View没有多大关系,只需要处理自身的移动操作即可。

public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mPointGapF.x = ev.getX();
                mPointGapF.y = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                scrollBy(0, (int) (mPointGapF.y - ev.getY()));
                mPointGapF.x = ev.getX();
                mPointGapF.y = ev.getY();
                break;
        }
        return true;
    }

外部拦截冲突

外部拦截冲突

1.2.内部拦截 

 运用2的知识,

ViewGroup : 只需在onInterceptTouchEventMotionEvent.ACTION_DOWN时候不拦截,其他时候都需要拦截,否则父类的onTouchEvent就不能处理任何事件了。

public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                return false;//down的时候拦截后,就只能交给自己处理了
        }
        return true;//如果不拦截,父类的onTouchEvent方法就无事件可以处理。
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_MOVE:
                scrollBy((int) (mPointGapF.x - ev.getX()), 0);

                mPointGapF.x = ev.getX();
                mPointGapF.y = ev.getY();
                break;
        }
        return super.onTouchEvent(ev);
    }

子View : 需要在ACTION_DOWN事件设置getParent().requestDisallowInterceptTouchEvent(true),并且在ACTION_MOVE的时候通过判断是否禁止父类的拦截。

 private boolean isSolve;
    private boolean isIntercept;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                isIntercept = false;
                isSolve = false;
                mPointGapF.x = ev.getX();
                mPointGapF.y = ev.getY();
                getParent().requestDisallowInterceptTouchEvent(true);
                break;

            case MotionEvent.ACTION_MOVE:
                if (!isSolve) {
                    isSolve = true;
                    isIntercept = (Math.abs(ev.getX() - mPointGapF.x) < Math.abs(ev.getY() - mPointGapF.y) * 2);
                    getParent().requestDisallowInterceptTouchEvent(isIntercept);
                }
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

2.案例2

2个滑动方向一致的滑动冲突,处理方法也跟案例1中的外部拦截方法一样,也是利用总结2中的知识点去解决:例如ScrollView与EditText的滑动冲突问题_z936689039的博客-CSDN博客

参考文章:

Android View的事件分发机制和滑动冲突解决_凶残的程序员-CSDN博客

猜你喜欢

转载自blog.csdn.net/z936689039/article/details/121598777