1、ViewGroup跟上一节View一样先看各种情况下的日志然后在根据日志情况来分析源码
1.1 在默认都存在的情况下日志
09-12 06:46:19.390 19085-19085/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 0
09-12 06:46:19.390 19085-19085/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 0
09-12 06:46:19.390 19085-19085/com.example.chao.viewontouch I/Tag: view -> dispatchTouchEvent -> 0
09-12 06:46:19.390 19085-19085/com.example.chao.viewontouch I/Tag: view -> onTouch
09-12 06:46:19.390 19085-19085/com.example.chao.viewontouch I/Tag: view -> onTouchEvent -> 0
09-12 06:46:19.410 19085-19085/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 2
09-12 06:46:19.410 19085-19085/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 2
09-12 06:46:19.410 19085-19085/com.example.chao.viewontouch I/Tag: view -> dispatchTouchEvent -> 2
09-12 06:46:19.410 19085-19085/com.example.chao.viewontouch I/Tag: view -> onTouch
09-12 06:46:19.410 19085-19085/com.example.chao.viewontouch I/Tag: view -> onTouchEvent -> 2
09-12 06:46:19.557 19085-19085/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 1
09-12 06:46:19.557 19085-19085/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 1
09-12 06:46:19.557 19085-19085/com.example.chao.viewontouch I/Tag: view -> dispatchTouchEvent -> 1
09-12 06:46:19.557 19085-19085/com.example.chao.viewontouch I/Tag: view -> onTouch
09-12 06:46:19.558 19085-19085/com.example.chao.viewontouch I/Tag: view -> onTouchEvent -> 1
09-12 06:46:19.561 19085-19085/com.example.chao.viewontouch I/Tag: view -> onClick
1.2 这次是取消onClickListener情况下日志 取消了onClickListener 等于没有消费事件
09-12 06:44:39.744 17254-17254/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 0
09-12 06:44:39.744 17254-17254/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 0
09-12 06:44:39.744 17254-17254/com.example.chao.viewontouch I/Tag: view -> dispatchTouchEvent -> 0
09-12 06:44:39.744 17254-17254/com.example.chao.viewontouch I/Tag: view -> onTouch
09-12 06:44:39.744 17254-17254/com.example.chao.viewontouch I/Tag: view -> onTouchEvent -> 0
09-12 06:44:39.744 17254-17254/com.example.chao.viewontouch I/Tag: ViewGroup -> onTouchEvent ->0
1.3 在view中的onTouchEvent 返回值为true
09-12 06:45:40.509 18253-18253/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 0
09-12 06:45:40.509 18253-18253/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 0
09-12 06:45:40.509 18253-18253/com.example.chao.viewontouch I/Tag: view -> dispatchTouchEvent -> 0
09-12 06:45:40.509 18253-18253/com.example.chao.viewontouch I/Tag: view -> onTouch
09-12 06:45:40.509 18253-18253/com.example.chao.viewontouch I/Tag: view -> onTouchEvent -> 0
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 2
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 2
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: view -> dispatchTouchEvent -> 2
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: view -> onTouch
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: view -> onTouchEvent -> 2
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 1
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 1
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: view -> dispatchTouchEvent -> 1
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: view -> onTouch
09-12 06:45:40.690 18253-18253/com.example.chao.viewontouch I/Tag: view -> onTouchEvent -> 1
1.4 在ViewGroup中的onInterceptTouchEvent返回true
09-12 05:51:04.638 21669-21669/com.example.chao.viewontouch I/Tag: ViewGroup -> dispatchTouchEvent -> 0
09-12 05:51:04.638 21669-21669/com.example.chao.viewontouch I/Tag: ViewGroup -> onInterceptTouchEvent -> 0
09-12 05:51:04.638 21669-21669/com.example.chao.viewontouch I/Tag: ViewGroup -> onTouchEvent ->0
接下来第二节来通过源码解析为什么会出现这种情况
首先还是找到ViewGroup的dispatchTouchEvent(ev)
boolean handled = false dispatchTouchEvent 返回值
接下来看这段话 这段话就清除所有的状态 resetTouchState() mFirstTouchTarget 也是在里面置空 mFirstTouchTarget 下面会讲到
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();
}
以下这段代码比较重要 第一次按下的话 actionMasked == MotionEvent.ACTION_DOWN 这个肯定是down事件 所以一定会进入if判断
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; 这段话就是判断子View有没有请求父控件不拦截 也就是这段 getParent().requestDisallowInterceptTouchEvent(true);
这里我们也没有调用这个方法 所以intercepted为false就是不拦截继续往下走
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;
}
接下来这段代码比较长 只取关键代码newTouchTarget = addTouchTarget(child, idBitsToAssign); addTouchTarget 这段对mFirstTouchTarget 和 newTouchTarget赋值
if (actionMasked == MotionEvent.ACTION_DOWN
|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
....
.....
if (newTouchTarget == null && childrenCount != 0) {
....
....
newTouchTarget = addTouchTarget(child, idBitsToAssign);
}
}
整个ViewGroup事件分发的核心就这这下面的代码了
// Dispatch to touch targets.
if (mFirstTouchTarget == null) {
// No touch targets so treat this as an ordinary view.
handled = dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS);
} else {
// Dispatch to touch targets, excluding the new touch target if we already
// dispatched to it. Cancel touch targets if necessary.
TouchTarget predecessor = null;
TouchTarget target = mFirstTouchTarget;
while (target != null) {
final TouchTarget next = target.next;
if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
handled = true;
} else {
final boolean cancelChild = resetCancelNextUpFlag(target.child)
|| intercepted;
if (dispatchTransformedTouchEvent(ev, cancelChild,
target.child, target.pointerIdBits)) {
handled = true;
}
if (cancelChild) {
if (predecessor == null) {
mFirstTouchTarget = next;
} else {
predecessor.next = next;
}
target.recycle();
target = next;
continue;
}
}
predecessor = target;
target = next;
}
}
经过上面的分析 我们知道 mFirstTouchTarget 是不为空 所以走else的代码块 我们看到 if (dispatchTransformedTouchEvent(ev, cancelChild,target.child, target.pointerIdBits))这里面
只看一部分
if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
event.setAction(MotionEvent.ACTION_CANCEL);
if (child == null) {
handled = super.dispatchTouchEvent(event);
} else {
handled = child.dispatchTouchEvent(event);
}
event.setAction(oldAction);
return handled;
}
如果说子 View 没有一个地方返回 true ,只会进来一次只会响应 DOWN 事件,代表不需要消费该事件,如果你想响应 MOVE,UP 必须找个地方ture对于ViewGroup来讲,如果你想拦截子 View 的 Touch 事件,可以覆写 onInterceptTouchEvent 返回 true 即可 , 如果说 onInterceptTouchEvent 返回的是 true 会执行该 ViewGroup 的 onTouchEvent 方法 , 如果子 View 没有消费 touch 事件也会调用该 ViewGroup 的 onTouchEvent 方法