滑动冲突的解决方案

一般来说,不管滑动冲突多么复杂,它都有既定的规则,他们之间的区别仅仅是滑动规则不同而已,抛开滑动规则来说,我们可以找到一种不依赖具体的滑动规则的通用解决方法。
以场景一为例,外部滑动方向和内部滑动方向不一致的情况,针对滑动冲突这里给出两种解决方式:外部拦截法和内部拦截法。
1、外部拦截法
外部拦截法是指点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,不需要就不拦截,这样就可以解决滑动冲突的问题。外部拦截法需要重写父容器的onInterceptTouchEvent方法,在内部做相应的拦截即可。伪代码如下

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean intercepted = false;
        int x  = (int) ev.getX();
        int y = (int) ev.getY();
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                intercepted = false;
                break;
            case MotionEvent.ACTION_MOVE:
                if (父容器需要当前的点击事件){
                    intercepted = true;
                }else {
                    intercepted = false;
                }
                break;
            case MotionEvent.ACTION_UP:
                intercepted = false;
                break;
                default:
                    break;
        }

        mLastXIntercept = x;
        mLastYIntercept = y;
        return intercepted;
}

针对不同的滑动冲突,只需要修改父容器需要的当前点击事件这个条件即可。首先ACTION_DOWN事件,父容器必须返回false,这是因为一旦父容器拦截了ACTION_DOWN,那么后续的ACTION_MOVE和ACTION_UP事件都会直接交给父容器处理,这个时候事件没法传递给子元素了。
2、内部拦截法
内部拦截法是指父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交给父容器进行处理。这种方法和Android的事件分发机制不一致,需要配合requestDisallowInterceptTouchEvent方法才能正常工作,使用起来比外部拦截法稍显复杂,它需要重写子元素的dispatchTouchEvent方法,伪代码如下:

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        int x = (int) ev.getX();
        int y = (int) ev.getY();

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                if (父容器需要的点击事件) {
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
            default:
                break;
        }
        
        mLastXIntercept = x;
        mLastYIntercept = y;
        return super.dispatchTouchEvent(ev);
    }

当面对不同的滑动策略时只需要修改里面的条件即可,其他不需要修改且不能修改。除了子元素需要做处理以外,父元素也要默认拦截除了ACTION_DOWN之外的其他事件,这样当子元素调用parent.requestDisallowInterceptTouchEvent(false)方法时,父元素才能继续拦截所需的是事件。
为什么父容器不能拦截ACTION_DOWN事件呢?那是因为ACTION_DOWN事件不受FLAG_DISALLOW_INTERCEPT这个标记位的控制,所以一旦父容器拦截了ACTION_DOWN事件,那么所有的事件都无法传递到子元素中去,这样内部拦截法就不起作用了。父元素所做的修改如下:

@Override
 public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN){
            return false;
        }else {
            return true;
        }
 }

可以看出内部拦截法没有外部拦截法简单易用,所以一般推荐外部拦截法来进行解决常见的滑动冲突。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值