1. 说明
上节课我们看了ViewGroup的事件分发,分别有dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent等3个方法,我们也分析了几种常见情况,那么我们这节课就来从源码的角度来对ViewGroup进行分析。
2. 分析
2.1 : dispatchTouchEvent()
boolean handled = false;
if (onFilterTouchEventForSecurity(ev)) {
final int action = ev.getAction();
final int actionMasked = action & MotionEvent.ACTION_MASK;
// 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();
}
/**
* Cancels and clears all touch targets.
*/
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();
}
}
}
/**
* Clears all touch targets.
*/
private void clearTouchTargets() {
TouchTarget target = mFirstTouchTarget;
if (target != null) {
do {
TouchTarget next = target.next;
target.recycle();
target = next;
} while (target != null);
mFirstTouchTarget = null;
}
}
以上代码只需要知道:
当手指按下时,是清除TouchTargets,也就是说会把 mFirstTouchTarget = null;
DOWN事件正常情况下会调用
intercepted = onInterceptTouchEvent(ev);
默认情况下onInterceptTouchEvent 返回false
if (!canceled && !intercepted) {
默认情况下是true,if语句可以执行
if (newTouchTarget == null && childrenCount != 0) {
DOWN的时候可以执行
for (int i = childrenCount - 1; i >= 0; i--) {
// 反序for循环
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
// 如果 子 View返回true,就会执行下边方法 ,下边方法主要是给 mFirstTarget=target ;赋值
newTouchTarget = addTouchTarget(child, idBitsToAssign);
}
}
}
}
// Canceling motions is a special case. We don't need to perform any transformations
// or filtering. The important part is the action, not the contents.
final int oldAction = event.getAction();
if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
event.setAction(MotionEvent.ACTION_CANCEL);
if (child == null) {
// 如果child == null ,会调用 自己的 super View.dispatchTouchEvent(event);
handled = super.dispatchTouchEvent(event);
} else {
// 如果child 不为null,会调用 子类的child.dispatchTouchEvent(event);
handled = child.dispatchTouchEvent(event);
}
event.setAction(oldAction);
return handled;
}
4. 事件分发总结
事件分发无非就是3个方法:
dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent,分别是事件分发、事件拦截、事件触摸;
对于自定义View来说:
如果该自定义View返回false,而不是返回true,表示不需要消费事件,那么就只会进来一次,只会相应DOWM事件,如果你想响应MOVE、UP事件,就必须找个地方返回true;
对于自定义ViewGroup来说:
如果你想拦截 子View 的 Touch事件,复写 onInterceptTouchEvent返回true即可;
如果说onInterceptTouchEvent 返回的是 true,表示ViewGroup会拦截事件,然后自己处理,这个时候会执行 ViewGroup的 onTouchEvent方法;
如果 子View没有一个地方返回 true,也就是说 子View没有消费 Touch事件,也会调用该 ViewGroup的 onTouchEvent