dispatchTouchEvent事件分发浅析(七)requestDisallowInterceptTouchEvent

上一篇,我们大体理解了对应的ACTION_DOWN 之后 对应的ACTION_MOVE 和 ACTION_UP 的简单过程 当然,还分是否消费等

具体代码可以见https://github.com/2954722256/demo_event

这篇,我们一起来看下简单了解下事件冲突 还有一个简单解决事件冲突的例子


requestDisallowInterceptTouchEvent方法说明

我们可以看看API 在android的sdk,对应的 XxxAndroidSdkDir/docs/reference/android/view/ViewGroup.html (因为这里不是将ViewGroup,所以其他略) 我们可以 搜索 requestDisallowInterceptTouchEvent, 找到对应的方法

    void requestDisallowInterceptTouchEvent(boolean disallowIntercept)

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

大概就是说,当 子View 不想被 父View 拦截的时候, 就可以调用requestDisallowInterceptTouchEvent(MotionEvent)方法, 这样,可以放父View的 onInterceptTouchEvent(MotionEvent)失效 (当然,还有其他情况,现在暂时略)


dispatchTouchEvent, onInterceptTouchEvent, requestDisallowInterceptTouchEvent简单关系

前面我们有说过,onInterceptTouchEvent 方法,只有ViewGroup有,并且默认是return false的

**onInterceptTouchEvent **

    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return false;
    }

那我们来看看 dispatchTouchEvent 方法 (我们先贴一下源码,再一起看看)

前面其实有一些修改Flags值的地方,暂时略

...前面省略...

        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;
    }
    ......
    if (!canceled && !intercepted) {
        ......

...后面省略...

这里我们可以看见,对应的判定, 都是和2个局部变量canceled 和 intercepted有关 canceled 先不考虑, intercepted 是和 mGroupFlags & FLAG_DISALLOW_INTERCEPT 有关 这2个变量,取与来判断 !=0 换句话说,就是对应的二进制码, 有没有都为 1 的地方。


mGroupFlags & FLAG_DISALLOW_INTERCEPT 简单分析

因为上面 intercepted 是和 mGroupFlags & FLAG_DISALLOW_INTERCEPT 有关 我们只要跟踪这2个变量,就可以大体找到对应的情况了

我们可以发现, mGroupFlags 和很多方法有关,方法中和很多二进制的变量有关,并且这些二进制码都不太一样, 比较复杂,只能暂时放一下 FLAG_DISALLOW_INTERCEPT 就比较简单点, 只和 dispatchTouchEventresetTouchState()requestDisallowInterceptTouchEvent 这3个方法有关 (先忽略resetTouchState()这个方法,也就是上面说的别的情况, dispatchTouchEvent上面已经贴了相关的代码) 这里我们贴一下 requestDisallowInterceptTouchEvent 方法实现

    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 = 0x80000; 这里是16进制的,16进制1位相当于2进制的4位, 8是2的3次方,也就是1000 后面4个0,换成2进制,也就是16个0 整体就是10000000000000000000, 也就是1后面19个0

我们可以发现,对应的16进制值对应位数上都是不同的2的次方数,换句话说,对应的2进制数值,对应的位的1值,是不会相同的 所以 mGroupFlags & FLAG_DISALLOW_INTERCEPT 判断的时候,只需要判断那个第20位的1,即可 而后面 mGroupFlags的取与,取非后的或, 都只会那个第20位的数字 (我们可以理解,这里 mGroupFlags , 就是很多Flag对应boolean值的集合,每一位就一个不同的Flag变量的boolean值容器思维上和 Bloom Filter 的实现理论相似

这里 requestDisallowInterceptTouchEvent 方法 其实,就是修改当前 mGroupFlags 对应 FLAG_DISALLOW_INTERCEPT 位上的boolean值,再如果有 父View,修改父View的 mGroupFlags 值

如果为true,则会执行后面的方法,修改 父View对应的 mGroupFlags 值


最后,我们回到 上面贴的 dispatchTouchEvent 方法中, 判断是否走onInterceptTouchEvent(ev)的地方 如果 disallowIntercept 为 false,就会走 再看下 disallowIntercept 的判断

final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;

这个地方,如果 mGroupFlags 对应位上是1, 就为true,就不会走

也就是 requestDisallowInterceptTouchEvent 设置 true, 就不会走 onInterceptTouchEvent(ev) 方法


ScrollView 与 WebView 的冲突

我们有的时候会遇到这种情况, 整个是 ScrollView ,内部有一个 WebView ,还有其他的一些 子View 这时候,WebView 显示不全 但是, 滑动的时候, 又会触发外面 ScrollView的上下滚动, 于是 内部的WebView就看不全了

Paste_Image.png

我们来看一下 ScrollView 的 onInterceptTouchEvent(MotionEvent ev) 方法

    final int action = ev.getAction();
    if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {
        return true;
    }
...后面省略...

换句话说,只要是 MotionEvent.ACTION_MOVE, 后面都不用看, 就会被拦截 那内部的 子View的滑动,肯定不会被监听到了

我们在搜索下 WebView 里面完全没有 requestDisallowInterceptTouchEvent 相关方法的调用

所以, ScrollView 中套用 WebView 肯定会有这样的问题


简单解决ScrollView 与 WebView 的冲突

根据上面的思路, 我们只需要 Override对应的 onInterceptTouchEvent(MotionEvent ev) 方法 调用 requestDisallowInterceptTouchEvent(true); 即可

经检验, 是可以的 (对应的代码,见上面的github地址,在 disallowintercept 的Module中)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Flutter入门到实战

WebView深度学习(二)之全面总结WebView遇到的坑及优化

这篇文章讲一下WebView遇到的那些坑,带领各位爬坑。这里如果有你没遇到的问题,欢迎留言告诉我,我尽我所能帮你解决。感谢大家支持。

92030
来自专栏技术小站

RESTful小拓展

RESTful 即Resource Representation State Transfer 相对应Resource 资源层,Representation 表...

15620
来自专栏日常分享

JSP/Servlet Web 学习笔记 DayTwo

   定义JSP文件中的全局属性、一个JSP页面可以包含多个page指令、除了Import以外,其他page指令定义的属性/值只能出现一次。

13520
来自专栏极客编程

ionic入门之AngularJS扩展

ionic是一个强大的混合式/hybridHTML5移动开发框架,特点是使用标准的HTML、 CSS和JavaScript,开发跨平台(目前支持:Android...

10610
来自专栏Flutter入门到实战

Weex初探--从安装到运行首个app

好多人说Weex跨平台不错,一直要推荐我玩一下,我就不信了,来安装玩一下试试效果。实践出真知!安装过程各种坑,工具太多了,太麻烦了,差点放弃(还好坚持下来呢)。

25930
来自专栏极客编程

Web前端都学点儿啥?

Web开发如今是如日中天,热的发烫。但是Web开发相关的技术和知识却像N座大山一样,耸立在我们面前,连绵起伏,漫无边际。那么这些山头那些我们应该占领,那些我们应...

11820
来自专栏技术小站

nginx 配置目录转发

server { listen 80; autoindex off; server_name image.imooc.com; ...

52120
来自专栏日常分享

JSP/Servlet Web 学习笔记 DayOne

  1)JSP是一种动态网页技术标准,它是在传统的页面HTML文件中插入Java程序段和JSP标记(tag),从而形成JSP文件(*.jsp),也称JSP页面。

11410
来自专栏技术小站

深入理解Java的接口和抽象类(转)

  对于面向对象编程来说,抽象是它的一大特征之一。在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类。这两者有太多相似的地方,又有太多不同的地方。很...

8620
来自专栏WD学习记录

html学习笔记1

1.网页文档的结构和格式的定义是由HTML元素来完成的.HTML元素是由单个或一对标签定义的范围。一个标签就是左右分别有(<)(>)的字符串。开始标签是指不以/...

12330

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励