场景:子View的滑动被父ViewGroup给拦截了
解决:在子View中调用requestDisallowInterceptTouchEvent();
问题:在什么时候调用 requestDisallowInterceptTouchEvent()?
截取一段源码,简单看一下实现,是什么原因导致的失效
ViewGroup.java
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
...
...
boolean handled = false;
if (onFilterTouchEventForSecurity(ev)) {
final int action = ev.getAction();
final int actionMasked = action & MotionEvent.ACTION_MASK;
if (actionMasked == MotionEvent.ACTION_DOWN) {
// 1
cancelAndClearTouchTargets(ev);
// 2
resetTouchState();
}
final boolean intercepted;
// 3
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
// 4
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action);
} else {
intercepted = false;
}
} else {
intercepted = true;
}
...
...
// 1 :cancelAndClearTouchTargets();
把 mFirstTouchTarget 置为 null
// 2 : resetTouchState();
清空 mGroupFlags & FLAG_DISALLOW_INTERCEPT
得出,导致失效的原因就是你在 DOWN “之前” 调用了requestDisallow..(),
然后 DOWN 的时候 mGroupFlags 和 FLAG_DISALLOW_INTERCEPT 被清零了,
所以在 MOVE 的时候 disallowIntercept 不满足条件,该拦截你还拦截你。
ok,我们屡一下流程。
- DOWN的时候,初始化了mFirstTouchTarget;
- MOVE的时候,符合条件,进入到注释3的 if 语句里,这时候 disallowIntercept 的值取决于你是否调用了requestDisallow..()
- 根据上面得出的,如果你在 DOWN“之前” 调用了requestDisallow,那你调用跟没调用一样,反正会被清空。
所以,解决办法是:
- 在子View的dispatch..或onIntercept..中 DOWN 的时候调用 requestDisallow..(true),
- 别忘了,在UP或CANCEL的时候,requestDisallow..(false)