事件分发机制是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逻辑运算相关的知识。

更多相关文章

  1. Android(安卓)和H5之间的交互-框架篇
  2. Android(安卓)MVP 架构改造 ~ 如何重用顶层业务
  3. broadcast基础
  4. android開發---周總結2
  5. android app的启动优化方法
  6. android解析xml文件的方式(其二)
  7. Android全局代理软件ProxyDroid和TransProxy源码分享
  8. Android(安卓)热修复一(热修复流程原理)
  9. Android实现通用的ActivityGroup(效果类似Android微博客户端主界

随机推荐

  1. android content providers相关
  2. 在android中用TimePicker和DatePicker或
  3. Android/ios/h5 三步调起QQ群聊,一键加群
  4. android构建自定义View和自定义组件
  5. Android 多进程学习
  6. Android TV apk移植到Android 9弹框概率
  7. android的国际化和本地化
  8. android selector 需要顺序的啊
  9. Android 中DatePicker和TimePicker 修改
  10. android中xml中的sax pull解析