继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

View事件体系之滑动冲突

明月笑刀无情
关注TA
已关注
手记 104
粉丝 17
获赞 57

滑动冲突三种情况

o    外部滑动方式与内部滑动方式不一样.

o    外部滑动方式与内部滑动方式一致.

o    上面两种情况的嵌套.

滑动冲突处理原则

对于上面的第一种情况

记录上次记录点减去当前点得到deltaX,deltaY

o    可以利用滑动路径和水平方向所形成的夹角来确定是那种滑动,如果小于45°,那自然就是横向,大于就是纵向.

o    可以对比横向滑动距离和纵向滑动距离,那个大就是那个方向滑动距离大.

对于第二,三种情况

可以 根据业务写出处理规则, 比如当内部View滑动到顶部或者底部时响应外部View,我们就可以根据这个规则判断内部View有没有滑动到底, 如果有的话就不消费事件,没有的话就消费事件.具体怎么消费事件有两种方法.

外部拦截法

所有的事件都要经由decorView分发,所以我们可以在decorView处做文章
如果父View需要事件,就拦截事件;否则就不拦截事件.具体实现在onInterceptTouchEvent()中处理.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public boolean onInterceptTouchEvent(MotionEvent event){
    boolean interceptd = false;
    //获取当前动作所在点
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch(event.getAction()){
        case MotionEvent.ACTION_DOWN:
        //默认不拦截ACTION_DOWN,因为父View一旦拦截ACTION_DOWN,那么这个系列的事件都会交由它处理.
            interceptd = false;
            break;
        case MotionEvent.ACTION_MOVE:
            if(父容器需要当前点击事件){
                interceptd = true;
            }else{
                interceptd = false;
            }
            break;
        case MotionEvent.ACTION_UP:
            //默认不拦截ACTION_UP,因为子View如果响应当前系列事件没有ACTION_UP的话无法触发onClick()方法
            interceptd = false;
            break;
        default:
            break;
    }
    //保存最后一个拦截点
    mLastXIntercept = x;
    mLastYIntercept = y;
    return interceptd;
}

内部拦截法

父容器默认不拦截任何事件,所有事件都交由子元素,子元素不需要再requestDisallowInterceptTouchEvent(boolean)操控父元素处理,和上面的方法正好相反.

Called when a child does not want this parent and its ancestors to intercept touch events with onInterceptTouchEvent(MotionEvent).

disallowIntercept(boolean)
boolean: True if the child does not want the parent to intercept touch events.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public boolean dispatchTouchEvent(MotionEvent event){
    //获取当前点位置
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch(event.getAction()){
        case MotionEvent.ACTION_DOWN:
            /**
            操控父元素不拦截ACTION_DOWN,因为ACTION_DOWN不受 ACTION_DISALLOW_INTERCEPT 标记控制,所以一旦父元素拦截ACTION_DOWN,这个事件系列都会被交由父元素处理.
            */
            parent.requestDisallowInterceptTouchEvent(true);
            break;
        case MotionEvent.ACTION_MOVE:
            int deltaX = X - mLastX;
            int deltaY = Y - mLastY;
            if(父容器需要此类事件){
                //让父元素可以继续拦截MOVE事件
                parent.requestDisallowInterceptTouchEvent(false);
            }
            break;
        case MotionEvent.ACTION_UP:
            break;
        default:
            break;
    }
    mLastX = x;
    mLastY = y;
    return super.dispatchTouchEvent(event);
}

父元素要做出如下处理

1
2
3
4
5
6
7
8
public boolean onInterceptTouchEvent(MotionEvent event){
    int action  = event.getAction();
    if(action == MotionEvent.ACTION_DOWN){
        return false;
    }else{
        return true;
    }
}

默认拦截除了ACTION_DOWN以外的事件.这样子元素调用requestDisallowInterceptTouchEvent(false)父元素才能继续拦截所需事件???

拦截方法对比

拦截方法

内部拦截法

外部拦截法

定义

父元素不拦截任何事件,所有事件都传给子元素

父元素需要就直接拦截,不需要就不拦截

重写

decorView的onInterceptTouchEvent()

子View的dispatchTouchEvent

默认

decorView不拦截ACTION_DOWN,不拦截ACTION_UP(1)

子元素默认拦截ACTION_DOWN;decorView不拦截ACTION_DOWN,拦截其他的(ACTION_MOVE,ACTION_UP)

原文链接:http://www.apkbus.com/blog-705730-62503.html

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP