说一说Android事件分发中的requestDisallowInterceptTouchEvent
Posted BennuCTech
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了说一说Android事件分发中的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事件中使用
以上是关于说一说Android事件分发中的requestDisallowInterceptTouchEvent的主要内容,如果未能解决你的问题,请参考以下文章