1爬虱、ViewGroup跟上一節(jié)View一樣先看各種情況下的日志然后在根據(jù)日志情況來分析源碼
1.1 在默認(rèn)都存在的情況下日志
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 等于沒有消費(fèi)事件
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
接下來第二節(jié)來通過源碼解析為什么會(huì)出現(xiàn)這種情況
首先還是找到ViewGroup的dispatchTouchEvent(ev)
boolean handled = false dispatchTouchEvent 返回值
接下來看這段話 這段話就清除所有的狀態(tài) resetTouchState() mFirstTouchTarget 也是在里面置空 mFirstTouchTarget 下面會(huì)講到
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 這個(gè)肯定是down事件 所以一定會(huì)進(jìn)入if判斷
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; 這段話就是判斷子View有沒有請(qǐng)求父控件不攔截 也就是這段 getParent().requestDisallowInterceptTouchEvent(true);
這里我們也沒有調(diào)用這個(gè)方法 所以intercepted為false就是不攔截繼續(xù)往下走
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;
}
接下來這段代碼比較長(zhǎng) 只取關(guān)鍵代碼newTouchTarget = addTouchTarget(child, idBitsToAssign); addTouchTarget 這段對(duì)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);
}
}
整個(gè)ViewGroup事件分發(fā)的核心就這這下面的代碼了
// 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;
}
}
經(jīng)過上面的分析 我們知道 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 沒有一個(gè)地方返回 true ,只會(huì)進(jìn)來一次只會(huì)響應(yīng) DOWN 事件,代表不需要消費(fèi)該事件,如果你想響應(yīng) MOVE,UP 必須找個(gè)地方ture對(duì)于ViewGroup來講俭驮,如果你想攔截子 View 的 Touch 事件,可以覆寫 onInterceptTouchEvent 返回 true 即可 , 如果說 onInterceptTouchEvent 返回的是 true 會(huì)執(zhí)行該 ViewGroup 的 onTouchEvent 方法 , 如果子 View 沒有消費(fèi) touch 事件也會(huì)調(diào)用該 ViewGroup 的 onTouchEvent 方法