requestDisallowInterceptTouchEvent实现原理

原创 2017年08月24日 12:04:37

我们为了让底部的控件处理事件,不被父控件拦截,一般我们会调用

v.getParent().requestDisallowInterceptTouchEvent(true);

来阻止父控件对事件的拦截,来看下它的实现原理。

首先明确下v.getParent()对于底部的View来说,得到的就是上层的父控件,也就是上层的ViewGroup,来看下ViewGroup的requestDisallowInterceptTouchEvent方法

@Override
    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {

        if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
            // We're already in this state, assume our ancestors are too
            return;
        }

        if (disallowIntercept) {
            mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
        } else {
            mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
        }

        // Pass it up to our parent
        if (mParent != null) {
            mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
        }
    }

首先就是判断是否已经设置过,如果没有,则在mGroupFlags中添加FLAG_DISALLOW_INTERCEPT这个标记位,接着如果该控件还有父控件,则一层一层在往上传递。
也就是说调用该方法就是将其上层所有控件的mGroupFlags中添加上FLAG_DISALLOW_INTERCEPT标记位。
那是怎么起到让父控件不拦截事件呢,我们知道事件的分发主要由三个方法决定dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent,我们看下ViewGroup的dispatchTouchEvent方法

    public boolean dispatchTouchEvent(MotionEvent ev) {
            ......
            if (actionMasked == MotionEvent.ACTION_DOWN) {
                cancelAndClearTouchTargets(ev);
                resetTouchState();
            }
            // Check for interception.
            final boolean intercepted;
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || mFirstTouchTarget != null) {
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                if (!disallowIntercept) {
                    intercepted = onInterceptTouchEvent(ev);
                    ev.setAction(action); // restore action in case it was changed
                } else {
                    intercepted = false;
                }
            } else {
                // There are no touch targets and this action is not an initial down
                // so this view group continues to intercept touches.
                intercepted = true;
            }
            ......
}

首先看下resetTouchState方法

private void resetTouchState() {
        clearTouchTargets();
        resetCancelNextUpFlag(this);
        mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
        mNestedScrollAxes = SCROLL_AXIS_NONE;
    }

关注点就是mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;也就是说如果是事件的起点,即MotionEvent.ACTION_DOWN的话就将标记位清除
接着就是关键点,决定是否调用onInterceptTouchEvent方法
我们看到第一个if中的判断语句为

actionMasked == MotionEvent.ACTION_DOWN
                    || mFirstTouchTarget != null

也就是说必须满足至少一个条件才有可能去执行onInterceptTouchEvent方法
1:事件为ACTION_DOWN事件
2:mFirstTouchTarget 不为空
我们看下mFirstTouchTarget 的说明

    // First touch target in the linked list of touch targets.
    private TouchTarget mFirstTouchTarget;

就是说mFirstTouchTarget 代表这个ViewGroup下第一个处理了事件的控件
要么为ACTION_DOWN事件,要么底下的控件处理了控件,反言之,如果这个ViewGroup曾经把事件交给下面的View去处理,而下面的View没有处理的话,那么下次事件ViewGroup的intercepted就直接被赋值为true,即将事件拦截,自己处理,好吧,这个很重要,但是和我们的requestDisallowInterceptTouchEvent关系也是不大
接着看第二个if判断语句

final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
     intercepted = onInterceptTouchEvent(ev);
     ev.setAction(action); // restore action in case it was changed
} else {
     intercepted = false;
}

disallowIntercept就是前面我们一直提到的标记位
如果disallowIntercept为false,也就是默认值,那么就会走正常的onInterceptTouchEvent去判断是否拦截,像RelativeLayout,LinearLayout这样的一般不需处理事件的ViewGroup一般都会返回false,事件还是会继续传递下去;但是像RecyclerView,ViewPager这些,他们往往会根据判断事件的具体情况,决定是否拦截,可能自己就将事件消费了
而如果disallowIntercept为true的话,即我们设置不允许父控件拦截事件,那么他的onInterceptTouchEvent方法就不会执行,intercepted直接设置为false,即不拦截事件,事件会传递给下层的View,当然了如果最终下面的View不争气,没有处理事件的话,那么根据我们上面说的,之后的事件在第一个if判断的时候就会决定事件不再往下传递了

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xw13782513621/article/details/77528518

Failed to contact Jack server

背景 很多人在开发中,拉下一套新的代码会出现下列错误: 1.Failed to contact Jack server; 2.No Jack Server running;//jack ser...
  • czy_1125
  • czy_1125
  • 2017-11-03 10:01:39
  • 63

网络数据请求展示为无限轮播图 ViewPager+XListView+Fragment+ImageLoader

一.  MainActivity.java package androidthree_1509d.MyViewpager; import android.support.v4.app.Fragm...
  • IT666DHW
  • IT666DHW
  • 2017-09-13 22:18:56
  • 229

VS2015配置open3.3.0

之前一直用的VS2010 + opencv2.4.9,有点落后了,电脑也比较差,这次索性咬咬牙,整了台联想拯救者,win10系统,安装了VS2015,下载了最新的open3.3。 安装配置过程如下: ...
  • helimin12345
  • helimin12345
  • 2017-10-25 23:24:51
  • 384

requestDisallowInterceptTouchEvent的用法

先来看下面的应用场景: 在布局文件中定义标签,然后在标签中定义一个标签。 现在TextView的长按事件可以弹出一个悬浮框,这个悬浮框是可以在屏幕上移动的。现在有个问题,就是在移动悬浮框的时候,悬浮框...
  • shineflowers
  • shineflowers
  • 2015-09-09 18:27:41
  • 3519

探究requestDisallowInterceptTouchEvent失效的原因

昨天在使用requestDisallowInterceptTouchEvent方法的时候,发现它失效了:在设置了requestDisallowInterceptTouchEvent(true)之后,父...
  • jiwangkailai02
  • jiwangkailai02
  • 2015-06-28 01:32:55
  • 10541

富文本编辑+fs操作文件+Buffer练习(头像上传功能)

富文本编辑内容引用=>1.UEditor是由百度web前端研发部开发所见即所得富文本web编辑器下载的文件 引入目录文件进来:文件上传功能引用文件: require(‘../ueditor/’);...
  • qq_26766283
  • qq_26766283
  • 2017-06-06 00:42:35
  • 7454

Android通过外部浏览器调用微信H5支付,Android+PHP详解

看了好多关于讲解微信H5支付开发的文章,大多数都是通过微信内部浏览器来调用支付接口(其实就是公众号支付),可能是因为H5支付接口刚开放不久吧。 微信官方体验链接:http://wxpay.wxu...
  • t6546545
  • t6546545
  • 2017-08-16 23:44:11
  • 4105

requestDisallowInterceptTouchEvent(true)的使用

当手指触摸到屏幕时,系统就会调用相应View的onTouchEvent,并传入一系列的action。当有多个层级的View时,在父层级允许的情况下,这个action会一直向下传递直到遇到最深层的Vie...
  • Scorpio_gao
  • Scorpio_gao
  • 2016-10-11 17:20:18
  • 752

自定义View有时在使用时设置requestDisallowInterceptTouchEvent(true)无效

有一次Activity中使用了自定义view,并在代码中设置requestDisallowInterceptTouchEvent(true)的时候,发现设置后并没有消耗onTouch的几种事件。父vi...
  • u010705554
  • u010705554
  • 2017-02-08 16:16:48
  • 600

Oracle错误——ORA-03113:通信通道的文件结尾 解决办法

Oracle错误——ORA-03113:通信通道的文件结尾 解决办法 2014-09-29 12:19 70743人阅读 评论(12) 收藏 举报  分类: java学习...
  • evilcry2012
  • evilcry2012
  • 2016-10-11 15:06:42
  • 1347
收藏助手
不良信息举报
您举报文章:requestDisallowInterceptTouchEvent实现原理
举报原因:
原因补充:

(最多只允许输入30个字)