前面我们讲到过onTouch事件的传递的原理,那么我们遇到事件冲突的时候就可以通过这个原理来设法处理了,一般来说我们分为父控件处理和子控件处理,其中子控件处理的时候会用到一个requestDisallowInterceptTouchEvent方法,接下来我们就一起来分析一下这个方法的原理以及使用时容易遇到的坑
我们之前讲到过onTouch事件的传递的原理,如果对这块不熟悉的朋友可以先看一下这个文章
onTouch事件的传递
http://blog.csdn.net/yulyu/article/details/56846752
requestDisallowInterceptTouchEvent,见名知意,主要的效果就是让控件的父控件不要调用onInterceptTouchEvent方法,并且不要拦截事件,这样子控件就能拿到所有的事件,然后根据自己的逻辑进行处理
//不要父控件拦截
getParent().requestDisallowInterceptTouchEvent(true);
//需要父控件考虑拦截
getParent().requestDisallowInterceptTouchEvent(false);
requestDisallowInterceptTouchEvent这个方法名太长,下面为了方便描述就用request代替
首先request的实现逻辑是在ViewGroup里面完成的
//ViewGroup.java
@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);
}
}
这里主要有两个地方要注意:
一个是这个方法是向上传递的,request里面又调用了父控件的request,也就是这个方法的效果是向上传递的
mParent.requestDisallowInterceptTouchEvent
一个是request方法里面主要是修改了mGroupFlags的值
(这里用的是 |= ,我们就不做详细的解释了,这里我们就简单的当作mGroupFlags= FLAG_DISALLOW_INTERCEPT)
mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
我们搜索一下FLAG_DISALLOW_INTERCEPT的引用,可以发现只有三个地方用到了他
dispatchTouchEvent里面的核心代码如下,主要就是指如果请求了不拦截,那么就不调用onInterceptTouchEvent
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;
}
这里我们就可以看出来request方法是怎么发生作用的了,但是我们刚才说了还有一个地方调用了FLAG_DISALLOW_INTERCEPT,那就是resetTouchState
/**
* Resets all touch state in preparation for a new cycle.
*/
private void resetTouchState() {
clearTouchTargets();
resetCancelNextUpFlag(this);
mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
mNestedScrollAxes = SCROLL_AXIS_NONE;
}
可以看出resetTouchState里面主要是做的一些还原处理,比如说将mGroupFlags设置为不等于FLAG_DISALLOW_INTERCEPT,那么resetTouchState又是什么时候被调用呢?
// Handle an initial down.
if (actionMasked == MotionEvent.ACTION_DOWN) {
cancelAndClearTouchTargets(ev);
resetTouchState();
}
我们搜索引用,可以看到在dispatchTouchEvent方法里面,当DOWN事件发生时,resetTouchState被调用了,于是mGroupFlags被设置为不等于FLAG_DISALLOW_INTERCEPT
如果不懂原理,那么requestDisallowInterceptTouchEvent使用时,会遇到一些奇怪的现象,只要我们注意两点,那么就不会再掉坑里去了