博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
requestDisallowInterceptTouchEvent调用时机分析
阅读量:5890 次
发布时间:2019-06-19

本文共 4507 字,大约阅读时间需要 15 分钟。

1.引言

写这边文章的初衷是因为经常有人看到说,父viewGroup的onInterceptTouchEvent返回true,子view调用requestDisallowInterceptTouchEvent(true)为什么还能实现子view可以捕获点击事件(其实这个问题一开始是错了),另外有人问用requestDisallowInterceptTouchEvent(true)到底应该在什么时候调用,是在子view的dispatchTouchEvent,onTouchEvent,onInterceptTouchEvent哪个方法,又应该在MotionEvent的Down,Up,Move的什么时候调用呢?其实这些问题根本还是对手势冲突有一点了解,但是又没理解透彻导致的,所以就有了这篇文章,希望有一定的启示作用。

2.Q1:父viewGroup的onInterceptTouchEvent返回true,子view调用requestDisallowInterceptTouchEvent(true)为什么还能实现子view可以捕获点击事件?

答:这个问题一开始就是错的,当我们的父ViewGroup不管在MotionEvent的哪种状态都返回true的话,子view是直接拿不到任何事件了,也就是说子view的dispatchTouchEvent,onTouchEvent,onInterceptTouchEvent都不会执行。为什么这样呢?看下代码ViewGroup的dispatchTouchEvent方法:

if (actionMasked == MotionEvent.ACTION_DOWN) {                // Throw away all previous state when starting a new touch gesture.                // The framework may have dropped the up or cancel event for the previous gesture                // due to an app switch, ANR, or some other state change.                cancelAndClearTouchTargets(ev);                resetTouchState();//1            }            // Check for interception.            final boolean intercepted;            if (actionMasked == MotionEvent.ACTION_DOWN                    || mFirstTouchTarget != null) {                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;                if (!disallowIntercept) {//2                    intercepted = onInterceptTouchEvent(ev);                    ev.setAction(action); // restore action in case it was changed                } else {                    intercepted = false;                }            }             ....                         if (!canceled && !intercepted) {//3             }

注释1:当ViewGroup拿到点击Down事件的时候,会重置mGroupFlags的值mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT,当执行boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;mGroupFlags & ~FLAG_DISALLOW_INTERCEPT& FLAG_DISALLOW_INTERCEPT很明显这个值就是为0,所以disallowIntercept为false,必然会进if的判断。

注释2:Intercepted的值被赋予了onInterceptTouchEvent(ev)的返回值,如果都是为true的话,那么注释3的if判断始终都进不去了,那么子view的一切点击事件都被拦截了。

2.Q2:按照上面的所说的,是不是子view调用requestDisallowInterceptTouchEvent(true)并不是万能,本来就不是万能,为什么我看到好像requestDisallowInterceptTouchEvent(true)都可以让子view拿到点击事件了?

答:在默认的情况下,ViewGroup的onInterceptTouchEvent的方法是这样的:

public boolean onInterceptTouchEvent(MotionEvent ev) {        if (ev.isFromSource(InputDevice.SOURCE_MOUSE)                && ev.getAction() == MotionEvent.ACTION_DOWN                && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)                && isOnScrollbarThumb(ev.getX(), ev.getY())) {            return true;        }        return false;    }

很明显当我们在手机上点击的时候,来源不是mouse的时候,返回的是false,以为这在下面这段代码当中,intercepted是为false的。

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

那这个时候Action_Down事件就被子View拦截到了,如果这个时候,我们在子view的Down事件里面调用requestDisallowInterceptTouchEvent(true)

@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;//1        } else {            mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;//2        }        // Pass it up to our parent        if (mParent != null) {            mParent.requestDisallowInterceptTouchEvent(disallowIntercept);        }    }

其实在这个方法中最重要的还是对mGroupFlags赋值,当为true的时候, mGroupFlags |= FLAG_DISALLOW_INTERCEPT,接下来,当move事件的时候,final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0的计算变成mGroupFlags | FLAG_DISALLOW_INTERCEPT & FLAG_DISALLOW_INTERCEPT这个的结果还是FLAG_DISALLOW_INTERCEPT,这个值在初始化的时候是protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;,所以不等于0,进而disallowIntercept为true,直接进入else方法,intercepted = false;接下来的move,up事件都能传递到子view上去了。

3.Q3调用时机?

答:综上所述,我们一个手势的操作,会经历down,move,up等操作,子view调用requestDisallowInterceptTouchEvent(true)的时间,是必须在能拿到点击事件,比如我们在down的时候调用了方法,接下来的move,up都会传到子view上了,如果是在子view的move方法中调用的话,那么要确认父view在move的过程中,能将事件传递给子view就好了。

4.demo:

转载地址:http://jmfsx.baihongyu.com/

你可能感兴趣的文章
我的友情链接
查看>>
字符串连接在不同浏览器中效率
查看>>
部署SQL Server2008 R2故障转移群集
查看>>
我的友情链接
查看>>
eclipes安装adt sdk
查看>>
pyhton学习之旅:python命名规范(转载)
查看>>
core_framework —— 基于libev的轻量级lua网络开发框架
查看>>
LVS NAT模式搭建
查看>>
吃到奖励变换子弹的方法
查看>>
varnish
查看>>
学习SEO需要掌握很多知识,在你决定学习SEO之前,先学习这些知识,以确保SEO可以顺利学习。...
查看>>
Android NDK编译选项设置
查看>>
交换机SPAN功能配置
查看>>
html 表单
查看>>
流氓软件捆绑IE代理无法上网解决办法
查看>>
大数据开发学习之Hive的动态分区
查看>>
mybatis
查看>>
序列、视图、索引(面试看这个就GO了)
查看>>
JSON 与 JS 对象的区别与对比
查看>>
Python学习笔记__6.4章 获取对象信息
查看>>