源码分析为什么requestDisallowInterceptTouchEvent(true)能阻止父View拦截事件
事件分发机制是Android中的一个难点,但是现在很多人都在写关于Android事件分发机制的文章,并且讲的都很不错,很多人也基本明白了事件是首先一级一级向下分发(如果父View不拦截的话,即父View的onInterceptTouchEvent方法返回false),交由子View去处理,然后子View再将事件的处理结果一级一级向上反馈,子View没有处理完(子View的onTouchEvent方法返回了false),那么事件又会向上传递给父View,交由父View进行处理。
很多时候子View并不希望父View拦截事件,这时我们该怎么做能够阻止父View拦截事件呢?首先我们看下ViewGroup的dispatchTouchEvent方法的部分源码:
// 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;}
从源码中我们可以看到这一句:
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
首先我们可以看到mGrouipFlag的声明protected int mGroupFlags;它并没有被赋值,因此默认为0,而FLAG_DISALLOW_INTERCEPT默认为0x80000,因此默认情况下(mGroupFlags & FLAG_DISALLOW_INTERCEPT) = 0,所以disallowIntercept为false,!disallowIntercept就为true了,因此代码接着向下执行intercepted = onInterceptTouchEvent(ev);即我们的父View会默认执行拦截事件。那我们怎么能够让父View默认不执行拦截事件呢,我们很多人都知道调用requestDisallowInterceptTouchEvent(true)方法就能够阻止父View拦截事件。那么为什么呢,接下来我们就从源码的角度来讲解这一句到底做了什么让父View就不拦截事件了,我们采用逆推的方法来说明。
要想让dispatchTouchEvent方法中intercepted = onInterceptTouchEvent(ev);这一句不执行,必须的保证disallowIntercept 为 true,即(mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;成立,现在我们就只要证明为什么(mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;一定成立,接着我们就要看requestDisallowInterceptTouchEvent()方法的源码了:
/** * {@inheritDoc} */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); }}
我们设置了参数disallowIntercept 为 true,首先我们看到该方法中的第一个判断
if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) { // We're already in this state, assume our ancestors are too return; }
1、假设(mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0) 为 true,此时if语句的条件成立,然后就return了,接着回到dispatchTouchEvent方法中,父View不拦截事件的要求就是要保证(mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;明显成立,所以父View将不会拦截事件。
2、假设(mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0) 为 false,因为disallowIntercept为true,因此会接着向下执行mGroupFlags |= FLAG_DISALLOW_INTERCEPT;即mGroupFlags = mGroupFlags | FLAG_DISALLOW_INTERCEPT;,然后我们回到dispatchTouchEvent方法中,父View不拦截事件的要求是要保证(mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;即(mGroupFlags | FLAG_DISALLOW_INTERCEPT & FLAG_DISALLOW_INTERCEPT) != 0成立,而这个又等价于 FLAG_DISALLOW_INTERCEPT != 0,显然FLAG_DISALLOW_INTERCEPT是不等于0的,所以条件成立,父View不会拦截事件。
至于为什么(mGroupFlags | FLAG_DISALLOW_INTERCEPT & FLAG_DISALLOW_INTERCEPT) != 0等价于FLAG_DISALLOW_INTERCEPT != 0,即为什么a | b & b = b,有兴趣的同学可以去了解java逻辑运算相关的知识。
更多相关文章
- Android(安卓)和H5之间的交互-框架篇
- Android(安卓)MVP 架构改造 ~ 如何重用顶层业务
- broadcast基础
- android開發---周總結2
- android app的启动优化方法
- android解析xml文件的方式(其二)
- Android全局代理软件ProxyDroid和TransProxy源码分享
- Android(安卓)热修复一(热修复流程原理)
- Android实现通用的ActivityGroup(效果类似Android微博客户端主界