Android中View的事件分发和拦截机制

博客转移到个人站点:
http://www.wangchengmeng.club/2018/02/04/Android%E4%B8%ADView%E7%9A%84%E4%BA%8B%E4%BB%B6%E5%88%86%E5%8F%91%E5%92%8C%E6%8B%A6%E6%88%AA%E6%9C%BA%E5%88%B6/

欢迎来吐槽

1.关系到事件分发和拦截机制的三个方法

1.dispatchTouchEvent(MotionEvent event)方法
2.onInterceptTouchEvent(MotionEvent event)方法
3.onTouchEvent(MotionEvent event)方法

2.dispatchTouchEvent(MotionEvent event)分发事件

*该方法主要是用来事件分发的,返回值有三种情况

    1.返回 super.dispatchTouchEvent(ev)
        会将事件分发下去
    2.返回true
        不会将事件分发下去,自己就调用当前View的onTouchEvent方法处理了
    3.返回false
        不会将事件分发下去

*该方法内部其实自己调用了onInterceptTouchEvent方法,进行事件拦截,默认情况下不会拦截事件,将事件放行。

*子View可以申请父View进行拦截/不拦截,其实也就是在内部判断是否调用onInterceptTouchEvent进行事件拦截。
    1.getParent().requestDisallowIntercept(true)
        申请父View不拦截,那就执行自己的onTouchEvent事件

    2.getParent().requestDisallowIntercept(false)
        申请拦截,父View将其事抢夺过来,执行父View的onTouchEvent事件

3.onInterceptTouchEvent(MotionEvent event)拦截事件

三种返回值:

    1.true
        将事件拦截,不在分发下去,执行当前View的onTouchEvent
    2.false
        将事件方法(默认就是放行),那子View会继续分发事件执行disPatchTouchEvent。
    3. super.onInterceptTouchEvent(ev)
                默认情况下不拦截

4.onTouchEvent(MotionEvent event)

是用来处理事件的,接收到分发的事件,就调用该方法去进行事件的处理

返回true,就不将事件回传给父View,自己消费掉
返回false和super.onTouchEvent(ev),将事件回传给父View,并由父View的的onTouchEvent来接收

5.Demo(案例)

1.两个ViewPager嵌套关系出现的问题。

当两个ViewPager嵌套的时候,(ViewPager自带滑动功能)在滑动内层(子)ViewPager的时候,在没有做处理的情况下,外层(父)的ViewPager会抢夺滑动事件,所以会出现,滑动子ViewPager的时候,父ViewPager滑动了,这种用户体验就很差


2.解决办法

    1)自定义一个类继承ViewPager,作为内层的ViewPafder

    2)复写onDispatchEvent(MptionEvent event)方法,

    3)定义条件,在满足什么样条件下申请父View不拦截或者拦截
        比如:在子ViewPager滑动到第一个页面并且从左往右滑动的时候,申请父View拦截,getParent().requestDisallowInterceptEvent(false),而子ViewPager默认到了第一个页面的时候,再继续向前一个不存在的页面是不能滑动的,这个时候父ViewPager就进行滑动,滑到子ViewPager最后一个页面并且继续从右往左滑动,同样的申请父View拦截。在其他情况下申请父View不拦截getParent().requestDisallowInterceptEvent(true),那么父ViewPager将不会个子ViewPager抢夺滑动事件,子ViewPager可以顺畅的滑动。


3.code(代码)

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {

    /***
     * 当多个view容器嵌套一起,事件分发机制会起冲突
     * 比如当两个ViewPager嵌套使用的时候,子ViewPager滑动的时候父Viewpager可能抢夺事件,
     * 这样滑动子ViewPager的时候,父ViewPager跟着滑动 这个时候我们只需要子ViewPager滑动,就可以
     * 使用requestDisallowInterceptTouchEvent(true)
     * 这个方法去申请父view容器的是否拦截,将其参数这是为true就是申请父view容器不拦截,不拦截子控件的事件,
     * 那子控件就做自己的onTouchEvent事件,父view容器就不会抢夺事件了,
     * 
     * 可以设置条件当子ViewPager滑动到第一个或者最后一个了,就可以申请拦截,那么子ViewPager不能滑动的时候
     * 父ViewPager在子ViewPager申请拦截之后就可以拦截子ViewPager,然后自己执行onTouchEvent事件
     */

    // 申请父控件不拦截
    getParent().requestDisallowInterceptTouchEvent(true);

    // 分析:
    // 当滑动到第一个页面,而且从左往右滑动的时候,就申请拦截,让父ViewPager滑动
    // 当滑动到最后一个页面的时候,而且从右往左滑动的时候,申请拦截
    // 其他情况申请不拦截,让子Viewpager滑动

    switch (ev.getAction()) {
    case MotionEvent.ACTION_DOWN:// 按下

        // 获取按下的X Y坐标
        downX = ev.getX();
        downY = ev.getY();

        break;
    case MotionEvent.ACTION_MOVE:// 移动
        // 获取移动的X Y 坐标
        float moveX = ev.getX();
        float moveY = ev.getY();
        float dX = downX - moveX;
        float dY = downY - moveY;
        // 如果Y轴方向移动,什么事情都不做,值关注横向滑动
        if (Math.abs(dX) > Math.abs(dY)) {
            // 表示横向移动
            // 如果是当前页面不是第一个页面 并且是从右往左滑动,申请不拦截
            if (getCurrentItem() != 0 && dX < 0) {

                getParent().requestDisallowInterceptTouchEvent(true);

            } else if (getCurrentItem() < getChildCount() - 1 && dX > 0) {
                //申请不拦截
                getParent().requestDisallowInterceptTouchEvent(true);

            } else {
                // 申请拦截
                getParent().requestDisallowInterceptTouchEvent(false);
            }
        }else{
            //纵向  申请拦截
            getParent().requestDisallowInterceptTouchEvent(false);
        }

        break;

    }
    //依然还是走父View中去分发事件
    return super.dispatchTouchEvent(ev);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值