View的滑动冲突

本文详细探讨了View在Android开发中遇到的滑动冲突问题,包括外部与内部滑动方向不一致的情况及其解决方案。介绍了外部拦截法和内部拦截法的具体实现,并解释了为何父容器不能拦截ACTION_DOWN事件。
摘要由CSDN通过智能技术生成

View的滑动冲突

  • 外部滑动方法和内部滑动方向不一致
    • 根据滑动时水平的还是竖直的
      • 滑动路径和水平方向所成的夹角
      • 水平方法和竖直方向的距离差
      • 水平和竖直方向的速度差来做判断
  • 外部滑动方向和内部滑动方向一致
    • 从业务上进行区分
  • 上面两种情况的嵌套
    • 用1和2的方法一起使用进行区分

解决方法

外部拦截法

父容器决定事件是否拦截

[伪代码]

public boolean onInterceptHoverEvent(MotionEvent event) {
    boolean intercepted = false;
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //必须为false
            //NOTE:如果在ACTION_DOWN返回true,那么后续的ACTION_MOVE和ACTION_UP
            //事件都会直接交给父容器处理,这个时候就没法再传递给子元素了
            intercepted = false;
            break;
        case MotionEvent.ACTION_MOVE:
            if (isParentNeed()) { //父容器需要当前点击事件
                intercepted = true;
            } else {
                intercepted = false;
            }
            break;
        case MotionEvent.ACTION_UP:
            //必须返回false,因为ACTION_UP本身没有太多意义
            intercepted = false;
            break;
        default:
            break;
    }

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

内部拦截法

父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交由父容器进行处理。需要requestDisallowInterceptTouchEvent方法。

[伪代码]

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

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

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

除了子元素需要做处理以外,父元素也要默认拦截除了ACTION_DOWN以外的其他事件,这样当子元素调用parent.requestDisallowInterceptTouchEvent(false)时,父元素才能继续拦截所需的事件。

public boolean onInterceptHoverEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        return false;
    } else {
        return true;
    }
}  

为什么父容器不能拦截ACTION_DOWN?
ACTION_DOWN事件不接受不接受FLAG_DISALLOW_INTERCEPT这个标志位的控制,所以一旦父容器拦截ACTION_DOWN事件,那么所有的事件都无法传递到子元素中去,这样内部拦截也就无法起作用了。

其他

笔记于《Android艺术开发探索》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

氦客

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值