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次。