Android-滑动冲突问题与解决

多个View嵌套使用既可能出现滑动冲突问题,实际上属于事件拦截与分发问题;

补充:
ViewGroup事件三个重要方法:onInterceptTouchEvent(),onTouchEvent(),dispatchTouchEvent();
View事件两个重要方法:onTouchEvent(),dispatchTouchEvent()
常见场景有3种:
场景1.内部View和外部View滑动方向不一致:通过滑动轨迹的方向就可以判断出当前应该分发给谁。
场景2.内部View和外部View滑动方向一致:要结合业务逻辑状态判断出当前应该分发给谁。
场景3.多层View嵌套,既有内部外部滑动方向不一致的情况,也有滑动方向一致的情况:将以上两种方法结合起来。

滑动冲突的处理规则:
规则1:当用户上下滑动的时候,需要让外部的View拦截事件,当用户左右滑动的时候,需要让内部的View拦截事件。
规则2:通常需要内部View响应View的滑动。

解决方法:
方法1:外部拦截法指事件都经过父容器(父布局)的拦截处理,如果父容器(父布局)需要此事件就拦截,如果子View需要此事件就不拦截。外部拦截法需要重写父容器的onInterceptTouchEvent()方法.
注意:
onInterceptTouchEvent()方法中,
ACTION_DOWN事件父容器必须返回false,这样事件才会传递到子元素;
ACTION_MOVE事件根据具体需求判断是否拦截,如果父容器需要拦截就返回true,否则返回false;
如果父容器在ACTION_UP时返回true,则子元素无法收到UP事件导致onClick事件失效。
父容器(父布局)

int lastInterceptX;
int lastInterceptY;
 
@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;
    }
 
    lastInterceptX = x;
    lastInterceptY = y;
    return intercepted;
}
方法2:内部拦截法指父容器(父布局)不拦截事件,所有的事件都传递到子元素(子布局),如果子元素(子布局)需要此事件就直接消耗,否则使用requestDisallowInterceptTouchEvent()通知父容器(父布局)处理。
注意:
子元素(子布局)dispatchTouchEvent()必须在ACTION_DOWN事件调用requestDisallowInterceptTouchEvent(true), 这样才能保证子元素(子布局)能收到ACTION_MOVE事件,在move事件做逻辑操作。 父容器的onInterceptTouchEvent()方法里的ACTION_DOWN事件不能拦截,这样子元素才能收到事件。
子元素(子布局)

int lastX;
int lastY;
@Override
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 dx = x - lastX;
            int dy = y - lastY;
            if (/*父容器需要此事件*/) {
                parent.requestDisallowInterceptTouchEvent(false);
            } else {
                parent.requestDisallowInterceptTouchEvent(true);
            }
            break;
        case MotionEvent.ACTION_UP:
            break;
    }
 
    lastX = x;
    lastY = y;
    return super.dispatchTouchEvent(event);
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值