说一说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只作用在部分情况下。



目录
相关文章
|
5月前
|
XML Java Android开发
Android Studio App开发之捕获屏幕的变更事件实战(包括竖屏与横屏切换,回到桌面与切换到任务列表)
Android Studio App开发之捕获屏幕的变更事件实战(包括竖屏与横屏切换,回到桌面与切换到任务列表)
45 0
“framework必会”系列:Android Input系统(一)事件读取机制
曾经在开发的很长一段时间内,笔者对点击事件的认知只存在于自定义View中的`onTouchEvent`等方法的处理。 后来慢慢的接触到`Android的事件分发机制`,但也只是在**Activity->ViewGroup->View**层面的分发逻辑
|
18天前
|
存储 Java Linux
Android系统获取event事件回调等几种实现和原理分析
Android系统获取event事件回调等几种实现和原理分析
31 0
|
18天前
|
传感器 Java API
Android Input系统(1) Input事件的产生与传递
Android Input系统(1) Input事件的产生与传递
20 0
|
5月前
|
小程序 JavaScript 前端开发
微信小程序(十七)小程序监听返回键跳转事件(安卓返回也适用)
onUnload:function(){ wx.redirectTo({ url: '../index/index' }) wx.navigateTo({ url: '../index/index' }) wx.switchTab({ url: '../../member/member' }) }
347 0
|
5月前
|
XML Java Android开发
Android App事件交互Event之模仿京东App实现下拉刷新功能(附源码 可直接使用)
Android App事件交互Event之模仿京东App实现下拉刷新功能(附源码 可直接使用)
37 0
Android App事件交互Event之模仿京东App实现下拉刷新功能(附源码 可直接使用)
|
5月前
|
XML Java Android开发
Android App事件交互中辨别缩放与旋转手指的讲解与实战(附源码 可直接使用)
Android App事件交互中辨别缩放与旋转手指的讲解与实战(附源码 可直接使用)
44 0
|
5月前
|
XML Java Android开发
Android App事件交互中区分点击和长按动作以及识别手势滑动方向的讲解及实战(附源码 可直接使用)
Android App事件交互中区分点击和长按动作以及识别手势滑动方向的讲解及实战(附源码 可直接使用)
71 0
|
5月前
|
XML Java Android开发
Android App开发触摸事件中手势事件Event的分发流程讲解与实战(附源码 简单易懂)
Android App开发触摸事件中手势事件Event的分发流程讲解与实战(附源码 简单易懂)
49 0
|
5月前
|
XML 监控 Java
Android App开发之事件交互Event中检测软键盘和物理按键讲解及实战(附源码 演示简单易懂)
Android App开发之事件交互Event中检测软键盘和物理按键讲解及实战(附源码 演示简单易懂)
156 0