前几天看了View分发的源码,弄懂了困惑已久的问题,特写此片以作记录,以免往后忘记.
当手机点击屏幕时会触发以下步骤 :
Activity--->Window---->PhoneWindow------->DecorView------->FrameLayout------------>ViewGroup
1. 当点击屏幕时Activity的dispatchTouchEvent会被触发
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
2.此时Activity又会调用Window的superDispatchTouchEvent(ev),因为Window抽象类,有一个实现类PhoneWindow
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
3.通过代码可知PhoneWindow又调用了 DecorView的superDispatchTouchEvent().
4.DecorView 又调用了FrameLaout的DispatchTouchEvent(),FrameLaout类中没有这个方法,他的父类ViewGroup的DispatchTouchEvent().
由于ViewGroup的DispatchTouchEvent()源码较长,此处只粘贴一部分!
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();
}
此处可知当按下屏幕的时候,会先调用这两个方法,这两个方法其实就是对数据进行初始化,下边是这两个方法的原型.
private void cancelAndClearTouchTargets(MotionEvent event) {
if (mFirstTouchTarget != null) {
boolean syntheticEvent = false;
if (event == null) {
final long now = SystemClock.uptimeMillis();
event = MotionEvent.obtain(now, now,
MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
syntheticEvent = true;
}
for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
resetCancelNextUpFlag(target.child);
dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
}
clearTouchTargets();
if (syntheticEvent) {
event.recycle();
}
}
}
看上边代码可知调用了 clearTouchTargets();此方法会把mFirstTouchTarget置为null
private void clearTouchTargets() {
TouchTarget target = mFirstTouchTarget;
if (target != null) {
do {
TouchTarget next = target.next;
target.recycle();
target = next;
} while (target != null);
mFirstTouchTarget = null;
}
}
往下看:
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;
}
假如此时父类设置了onInterceptTouchEvent为true,那么此时intercepted为true.