Connor学Android - View滑动冲突

在这里插入图片描述

Learn && Live

虚度年华浮萍于世,勤学善思至死不渝

前言

Hey,欢迎阅读Connor学Android系列,这个系列记录了我的Android原理知识学习、复盘过程,欢迎各位大佬阅读斧正!原创不易,转载请注明出处:http://t.csdn.cn/c1S1X,话不多说我们马上开始!

1.滑动冲突场景

(1)外部与内部滑动方向不一致

(2)外部与内部滑动方向一致,常见,如ScrollView嵌套RecyclerView

(3)上面两种情况的嵌套

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5nMNbGBc-1657196736636)(F:\yhy925\dailylife\Work\2.Android\《Android开发艺术探索》笔记\4.View\5.View冲突场景.png)]

2.滑动冲突的处理规则

(1)针对场景1,左右滑动时让外部的View拦截点击事件,上下滑动时让内部的View拦截点击事件

(2)针对场景2,可以根据业务的不同需求进行处理,如当处于某种状态时需要外部View响应用户的滑动,而处于另一状态时则需要内部View来响应滑动

(3)针对场景3,与场景2类似,无法直接根据滑动的角度、速度差、距离差来判断,只能从业务的需求上得出相应的处理规则

3.滑动冲突的解决方式

外部拦截法

指点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,如果不需要此事件就不拦截。此方法需要重写父容器的onInterceptTouchEvnet方法,在内部做相应的拦截

//此方法一般用于事件拦截
public boolean onInterceptTouchEvent(MotionEvent ev) {
    boolean interceoted = false;
    int x = (int) ev.getX();
    int y = (int) ev.getY();
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            interceoted = false;
            break;
        case MotionEvent.ACTION_MOVE:
            // 判断是否拦截
            if (满足父容器拦截要求){
                interceoted=true;
            }else{
                interceoted=false;
            }
            break;
        case MotionEvent.ACTION_UP:
            interceoted=false;
            break;
    }
    mLastXIntercept = x;
    mLastYIntercept = y;
    return interceoted;
}

(1)不可以拦截ACTION_DOWN事件,因为一旦拦截则后续的MOVE、UP事件都会直接交由父容器处理,无法传递给子元素

(2)ACTION_MOVE事件根据需要决定是否拦截

(3)ACTION_UP必须返回false,如果返回true,并且滑动事件交给子View处理,那么子View将收不到 ACTION_UP事件,子View的 onClick事件也将无法触发。而父View不一样,如果父View在 ACTION_MOVE中开始拦截,除了一个ACTION_CANCEL传递给子View,那么后续的所有都将默认交给父View处理,所以ACTION_UP父View还是可以收到。

内部拦截法

指父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就拦截,否则交给父容器处理。由于涉及子元素控制父容器是否拦截,需要调用requestDisallowInterceptTouchEvent方法

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

    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            // 禁用父布局拦截事件,从而失去后续Action(即失去)
            getParent().requestDisallowInterceptTouchEvent(true);
            break;
        case MotionEvent.ACTION_MOVE:
            int deltaX=x-mLastX;
            int deltaY=y-mLastY;
            if (父容器需要此类点击事件){
                getParent().requestDisallowInterceptTouchEvent(false);
            }
            break;
        case MotionEvent.ACTION_UP:
            break;
    }
    mLastX=x;
    mLastY=y;
    return super.dispatchTouchEvent(ev);
}

父容器也需要重写onInterceptTouchEvnet()方法,拦截除ACTION_DOWN以外的其他事件

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

(1)父容器不能拦截DOWN事件,因为ACTION_DOWN事件不受标记位FLAG_DISALLOW_INTERCEPT的限制,所以一旦父容器拦截了DOWN事件,后续事件都无法传递到子元素中去

(2)内部拦截法的操作要稍微复杂一些,因此更推荐使用外部拦截法来解决常用的滑动冲突

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ConnorYan

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

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

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

打赏作者

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

抵扣说明:

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

余额充值