说一说Android事件分发中的requestDisallowInterceptTouchEvent

简介: 我们知道在事件分发过程中是存在一个拦截机制的onInterceptTouchEvent当它返回true则不向下分发事件,否则向下分发。但是在这个过程中,还有一个参与者:requestDisallowInterceptTouchEvent,这个函数直接影响事件的拦截。我们今天就来说一说这个这个函数是如何影响事件分发的。

前言


我们知道在事件分发过程中是存在一个拦截机制的


onInterceptTouchEvent
复制代码


当它返回true则不向下分发事件,否则向下分发。

但是在这个过程中,还有一个参与者: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);
    }
}
复制代码


可以看到它改变了一个开关FLAG_DISALLOW_INTERCEPT,同时调用其parent的函数。

那么这个开关有什么用?

在ViewGroup的dispatchTouchEvent函数开头有这样一段代码:


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;
}
复制代码


先来看判断逻辑,当是down事件或者mFirstTouchTarget不为空,则进入一个代码段;否者拦截设置为true。

我们知道down事件分发过程中,如果有子view消费事件,则赋值给mFirstTouchTarget,后续事件会直接分发给mFirstTouchTarget

这里也可以看出,如果有子View消费了down事件,即mFirstTouchTarget不为空,所以后续事件还会检查拦截。


所以上面就可以理解了,如果down事件中没有子view消费事件,那么后续事件的拦截都为true。所以后续事件不会再遍历子View。

下面再看if代码段

一开始就使用了FLAG_DISALLOW_INTERCEPT开关,即disallowIntercept

disallowIntercept为true,则不拦截;否者判断onInterceptTouchEvent

所以简单来说requestDisallowInterceptTouchEvent设置为true可以跳过onInterceptTouchEvent,不拦截事件。

而且因为requestDisallowInterceptTouchEvent又调用了parent的函数,所以所有层次的父view都不再拦截。

所以requestDisallowInterceptTouchEvent的功能是让这个view及上面的所有父view都放开拦截,即使onInterceptTouchEvent为true。

所以我们一般如下使用


view.getParent().requestDisallowInterceptTouchEvent(true);
复制代码

这样view的所有层次的父view都不会拦截事件了。


扩展思考


下面让我们再深入想想。上面这种的情况是在touch事件发生前设置onInterceptTouchEvent,也是我们一般的用法。但是如果事件发生过程中调用这个函数呢?

比如在view的onTouch的某个事件中使用


getParent().requestDisallowInterceptTouchEvent(true)
复制代码


当事件开始分发时,down事件进入父view的dispatchTouchEvent时,这是子view还未得到事件,所以没有设置requestDisallowInterceptTouchEvent

这时如果父view的onInterceptTouchEvent返回true,即拦截的话,事件则不会分发给子view了,所以requestDisallowInterceptTouchEvent永远不会执行,子view则无法得到事件。

但是如果父view的onInterceptTouchEvent返回false,即不拦截的话,事件就可以分发到子view,requestDisallowInterceptTouchEvent执行,之后的事件都会跳过父view的onInterceptTouchEvent的判断

例如父view的onInterceptTouchEvent代码如下


public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                return false;
            case MotionEvent.ACTION_MOVE:  
                    return true;
            case MotionEvent.ACTION_UP:
                return true;
            default:
                break;
        }
        return false;   
    }
复制代码


down事件不进行拦截,但是拦截了move和up事件。

如果子view的onTouch的down事件中使用


getParent().requestDisallowInterceptTouchEvent(true)
复制代码


这样down事件分发到了子view,执行了requestDisallowInterceptTouchEvent,同时返回了true。随后move或up事件分发到父view时,因为被设置了FLAG_DISALLOW_INTERCEPT标签,所以就会跳过onInterceptTouchEvent。

所以onInterceptTouchEvent中move和up的返回值设置就无效了,因为根本就不再执行这个函数了。


总结


通过上面的分析可以知道requestDisallowInterceptTouchEvent会让父view放开拦截,并且是向上层层生效的。同时我们也可以通过一些逻辑控制,使requestDisallowInterceptTouchEvent只作用在部分情况下。



目录
相关文章
|
20天前
|
Android开发
Android面试高频知识点(1) 图解Android事件分发机制
Android面试高频知识点(1) 图解Android事件分发机制
|
24天前
|
Android开发
Android面试高频知识点(1) 图解 Android 事件分发机制
Android面试高频知识点(1) 图解 Android 事件分发机制
37 1
|
29天前
|
XML 前端开发 Android开发
Android面试高频知识点(1) 图解Android事件分发机制
Android面试高频知识点(1) 图解Android事件分发机制
Android面试高频知识点(1) 图解Android事件分发机制
|
1月前
|
Android开发
Android 事件分发机制详细解读
Android 事件分发机制详细解读
38 4
|
3月前
|
图形学 Android开发
小功能⭐️Unity调用Android常用事件
小功能⭐️Unity调用Android常用事件
|
3月前
|
Android开发
Android面试高频知识点(1) 图解 Android 事件分发机制
在Android开发中,事件分发机制是一块Android比较重要的知识体系,了解并熟悉整套的分发机制有助于更好的分析各种点击滑动失效问题,更好去扩展控件的事件功能和开发自定义控件,同时事件分发机制也是Android面试必问考点之一,如果你能把下面的一些事件分发图当场画出来肯定加分不少。废话不多说,总结一句:事件分发机制很重要。
193 9
|
3月前
|
开发工具 Android开发
Android项目架构设计问题之组件A通知组件B某个事件的发生如何解决
Android项目架构设计问题之组件A通知组件B某个事件的发生如何解决
39 0
|
5月前
|
Android开发
39. 【Android教程】触摸事件分发
39. 【Android教程】触摸事件分发
43 2
|
5月前
|
XML Android开发 数据格式
37. 【Android教程】基于监听的事件处理机制
37. 【Android教程】基于监听的事件处理机制
81 2
|
6月前
|
存储 Java Linux
Android系统获取event事件回调等几种实现和原理分析
Android系统获取event事件回调等几种实现和原理分析
341 0