View的事件處理:
dispatchTouchEvent -> onTouchEvent -> performClick -> 如果設置了setOnClickListener,那麼此時就會調用。
注意:如果View設置了setOnTouchListener,並且在回調方法onTouch裏面return true,那麼View的onTouchevent方法就不會執行,當然setOnClickListener的回調就更不會執行了。
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
ViewGroup的事件處理:
dispatchTouchEvent -> dispatchTransformedTouchEvent -> super.dispatchTouchEvent or child.dispatchTouchEvent
注意:mFirstTouchTarget這個參數非常的重要,
1.在事件ACTION_DOWN、ACTION_POINTER_DOWN、ACTION_HOVER_MOVE中,遍歷子View,調用dispatchTransformedTouchEvent -> child.dispatchTouchEvent -> child.onTouchEvent,如果返回true,那麼就會將子View通過addTouchTarget加入到mFirstTouchTarget鏈表的頭部。
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
// Child wants to receive touch within its bounds.
mLastTouchDownTime = ev.getDownTime();
if (preorderedList != null) {
// childIndex points into presorted list, find original index
for (int j = 0; j < childrenCount; j++) {
if (children[childIndex] == mChildren[j]) {
mLastTouchDownIndex = j;
break;
}
}
} else {
mLastTouchDownIndex = childIndex;
}
mLastTouchDownX = ev.getX();
mLastTouchDownY = ev.getY();
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
}
2.其他事件,就會去判斷mFirstTouchTarget是否爲null,如果爲null,則後續調用super.dispatchTouchEvent;如果不爲null,則依次遍歷mFirstTouchTarget,分別調用mFirstTouchTarget.child.dispatchTouchEvent。
// 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 {
//這裏的intercepted會受onInterceptTouchEvent方法的返回值影響,一旦intercepted爲true,將會把mFirstTouchTarget全部清除,並且對所有的target.child發送ACTION_CANCEL事件
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;
}
}
這裏需要注意的是如果onInterceptTouchEvent返回爲true,那麼會給mFirstTouchTarget中所有的View分發ACTION_CANCEL事件,並且將mFirstTouchTarget中所有的Target全部移除掉,因此如果一個事件序列如果onInterceptTouchEvent返回爲true,那麼後續事件都不會分發給子View了,除非有一個新的事件ACTION_POINTER_DOWN的到來。
多點觸控:
注意:一個View裏面只能收到一次ACTION_DOWN事件,多次ACTION_POINTER_DOWN事件。但是如果是ViewGroup接受到ACTION_POINTER_DOWN事件,且第二個手指與第一個手指處於不同的兩個View,那麼會調用MotionEvent.split方法將ACTION_POINTER_DOWN變成ACTION_DOWN事件,傳遞給新的touchTarget.child中,因此在ViewGroup看來是接收到了一次ACTION_DOWN事件,但是不同的兩個View分別接收到了一次ACTION_DOWN事件,總計爲2次。