關(guān)鍵源碼(對dispatchTouchEvent()的重要部分)
片段一 是否攔截事件
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;
}
片段二 如果ViewGroup不攔截事件
if (!canceled && !intercepted) {
for(遍歷child){
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
newTouchTarget = addTouchTarget(child, idBitsToAssign);
break;
}
}
}
片段三 有無Child處理事件
if (mFirstTouchTarget == null) {
// No touch targets so treat this as an ordinary view.
handled = dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS);
}else{
// 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;//攔截時蠢熄,cancelChild為true
if (dispatchTransformedTouchEvent(ev, cancelChild,
target.child, target.pointerIdBits)) {
handled = true;
}
if (cancelChild) {
if (predecessor == null) {
mFirstTouchTarget = next;//會將mFirsrtTouchTarget置空
} else {
predecessor.next = next;
}
target.recycle();
target = next;
continue;
}
}
predecessor = target;
target = next;
}
if (canceled
|| actionMasked == MotionEvent.ACTION_UP
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
resetTouchState();
}
}
}
disallowIntercept 默認(rèn)值為false,通過viewGroup.requestDisallowInterceptTouchEvent(boolean)進(jìn)行設(shè)置。本文只討論disallowIntercept 為false的情況穗酥。
mFirstTouchTarget==null 沒有child處理事件护赊,有兩種可能
- ViewGroup攔截了事件
- ViewGroup沒有攔截了事件,但是沒有child處理事件
mFirstTouchTarget!=null 有child處理事件
- ViewGrop沒有攔截事件砾跃,且有child消費了事件
intercepted表示是否攔截事件,值為true表示攔截事件节吮。
對ACTION_DOWN事件的處理
- 由onInterceptTouchEvent()判斷是否攔截(片段一)
- 如果ViewGroup攔截事件抽高,則遍歷child,將事件交給child處理,如果有child消耗了事件透绩,則調(diào)用addTouchTarget()給mFirstTouchTarget賦值翘骂。(片段二)
- 如果child不消費ACTION_DWON(mFirstTouchTarget==null),則ViewGroup處理該ACTION_DOWN事件。(片段三)
對ACTION_MOVE事件的處理
- 如果有child消費正在處理事件( mFirstTouchTarget != null),則由onInterceptTouchEvent()判斷是否攔截帚豪,否則攔截事件(片段一)
- 如果ViewGroup攔截ACTION_MOVE事件碳竟,則遍歷child,將事件交給child處理,如果有child消費了事件狸臣,則調(diào)用addTouchTarget()給mFirstTouchTarget賦值莹桅。(片段二)
- 如果沒有child消費正在處理事件(mFirstTouchTarget==null),則ViewGroup處理該ACTION_MOVE事件,否則 如果ViewGroup攔截了ACTION_MOVE,則mFirstTouchTarget設(shè)置為空烛亦。(片段三)
對ACTOIN_UP事件的處理
- 如果有child正在處理事件( mFirstTouchTarget != null)诈泼,則由onInterceptTouchEvent()判斷是否攔截,否則攔截事件(片段一)
- 如果ViewGroup攔截ACTION_UP事件,則遍歷child,將事件交給child處理,如果有child消耗了事件凳宙,則調(diào)用addTouchTarget()給mFirstTouchTarget賦值兴猩。(片段二)
- 如果沒有child正在消費事件,則ViewGroup處理該ACTION_MOVE事件卖漫,
否則- 如果ViewGroup攔截了ACTION_UP,則mFirstTouchTarget設(shè)置為空。
- 重置TouchState狀態(tài)
總結(jié)
ACTION_DWON作為起始動作,所以要判斷是否攔截
ACTION_MOVE,ACTION_UP作為后續(xù)事件
如果child在處理事件杭抠,ViewGroup要判斷是否攔截事件;
如果沒有child在處理事件知牌,ViewGroup自然攔截事件祈争。
如果ViewGroup不攔截事件,事件交給child處理角寸。
如果沒有Child正在處理事件菩混,則事件交給ViewGroup處理;
如果有Child正在處理事件忿墅,此時如果ViewGroup攔截了當(dāng)前的事件,則要將ViewGroup標(biāo)志位正在處理事件即mFirstTouchTarget設(shè)置為空沮峡。