Android学习之view滑动冲突

常见的滑动冲突的场景一般可分为三种:

场景一、外部滑动方向与内部滑动方向不一致

场景二、外部滑动方向与内部滑动方向一致

场景三、上面两种情况的嵌套

第一种场景:

由于外部与内部的滑动方向不一致,那么可以根据当前滑动方向,水平还是垂直来判断这个事件到底该交给谁来处理。

至于如何获得滑动方向,可以得到滑动过程中的两个点的坐标。一般情况下根据水平和竖直方向滑动的距离差就可以判断方向,

当然也可以根据滑动路径形成的夹角(或者说是斜率如下图)、水平和竖直方向滑动速度差来判断。

第二种场景:

由于外部与内部的滑动方向一致,那么不能根据滑动角度、距离差或者速度差来判断。这种情况下必需通过业务逻辑来进行判断。

滑动冲突解决

1、 外部拦截法:

父View根据需要对事件进行拦截。逻辑处理放在父View的onInterceptTouchEvent方法中。

只需要重写父View的onInterceptTouchEvent方法,并根据逻辑需要做相应的拦截即可。

	public boolean onInterceptTouchEvent(MotionEvent event) {
        boolean intercepted = false;
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.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;
    }

<1> 根据业务逻辑需要,在ACTION_MOVE方法中进行判断,如果需要父View处理则返回true,否则返回false,事件分发给子View去处理。

<2> ACTION_DOWN 一定返回false,不要拦截它,否则根据View事件分发机制,后续ACTION_MOVE 与 ACTION_UP事件都将默认交给父View去处理

<3> ACTION_UP也需要返回false,如果返回true,并且滑动事件交给子View处理,那么子View将接收不到ACTION_UP事件,子View的onClick事件也无法触发。

2、 内部拦截法:

父View不拦截任何事件,所有事件都传递给子View,子View根据需要决定是自己消费事件还是给父View处理。

这需要子View使用requestDisallowInterceptTouchEvent方法才能正常工作。

View的dispatchTouchEvent方法

	public boolean dispatchTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                parent.requestDisallowInterceptTouchEvent(true);
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                int deltaX = x - mLastX;
                int deltaY = y - mLastY;
                if (父容器需要此类点击事件) {
                    parent.requestDisallowInterceptTouchEvent(false);
                }
                break;
            }
            case MotionEvent.ACTION_UP: {
                break;
            }
            default:
                break;
        }

        mLastX = x;
        mLastY = y;
        return super.dispatchTouchEvent(event);
    }

父View需要重写onInterceptTouchEvent方法:

	public boolean onInterceptTouchEvent(MotionEvent event) {

        int action = event.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            return false;
        } else {
            return true;
        }
    }

<1> 内部拦截法要求父View不能拦截ACTION_DOWN事件,由于ACTION_DOWN不受FLAG_DISALLOW_INTERCEPT标志位控制,一旦父容器拦截ACTION_DOWN那么所有的事件都不会传递给子View。

<2> 滑动策略的逻辑放在子View的dispatchTouchEvent方法的ACTION_MOVE中,如果父容器需要获取点击事件则调用 parent.requestDisallowInterceptTouchEvent(false)方法,让父容器去拦截事件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值