坑
在處理自定義View有事會使用requestDisallowInterceptTouchEvent(true)來屏蔽父類中的onInterceptTouchEvent()方法。但發(fā)現調用之后有時不起作用。查看源碼,確實requestDisallowInterceptTouchEvent()方法設置的mGroupFlags標志位是用來控制onInterceptTouchEvent()方法的調用。
ViewGroup中dispatchTouchEvent部分源碼
// Handle an initial down.
if (actionMasked == MotionEvent.ACTION_DOWN) {
// Throw away all previous state when starting a new touch gesture.
// The framework may have dropped the up or cancel event for the previous gesture
// due to an app switch, ANR, or some other state change.
cancelAndClearTouchTargets(ev);
resetTouchState();
}
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;
}
填
問題就出在了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;
}
雖然我們設置了requestDisallowInterceptTouchEvent(true),但每次dispatchTouchEvent()調用時都會重置mGroupFlags標志位,所以在判斷disallowIntercept是只要是ACTION_DOWN事件時永遠是false。所以ACTION_DOWN被攔截了基本沒戲了,其他事件只能從mFirstTouchTarget != null上下手了。mFirstTouchTarget是在intercepted為false時賦值的。所以讓onInterceptTouchEvent()在ACTION_DOWN事件是返回false即可。所以可以集成該類,復寫其onInterceptTouchEvent()方法。
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
return false;
break;
default:
return super.onInterceptTouchEvent(ev);
break;
}
}
這樣在其子類的onTouchEvent()方法中調用getParent().requestDisallowInterceptTouchEvent(true);就可以生效了。
參考博客
http://blog.csdn.net/jiwangkailai02/article/details/46666147
http://blog.csdn.net/u014623470/article/details/51658609