0%

ViewGroup.dispatchTouchEvent()分析

ViewGroup.dispatchTouchEvent()分析

流程图:
dispatchTouchEvent


拦截检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Check for interception.
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;
}

分析:

  1. 如果是ACTION_DOWN事件,则检查是否需要拦截。如果不是ACTION_DOWN事件,比如是ACTION_MOVE事件,则看mFirstTouchTarget的情况,若在之前的事件中有childView想处理touch事件,则mFirstTouchTarget不为空,即需要向下传递touch事件,这时候也需要检查是否需要拦截。
  2. 不是ACTION_DOWN事件, 并且mFirstTouchTarget为空,即不需要向下传递touch事件, 这时候可以直接设置intercepted=true,后续便不会向下传递事件。

不拦截,查找可以接收事件的子View

1
2
3
4
5
6
7
if (!canceled && !intercepted) {
if (actionMasked == MotionEvent.ACTION_DOWN
|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {

}
}

分析:

  1. 如果不是取消动作,并且不拦截事件,再如果是ACTION_DOWN事件,则查找一个可以接收这次事件的childView。若存在的话,则为mFirstTouchTarget赋值,不再为空。
  2. 只有添加到mFirstTouchTarget的childView才会收到后续的touch事件,childView需要在ACTION_DOWN事件中return true才会被添加到mFirstTouchTarget。

如何分发

//最后一组操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 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;
}
}

分析:

  1. mFirstTouchTarget为空,即不需要往下传递,则最终会调用super.dispatchTouchEvent(), ViewGroup继承于View,即执行了View.dispatchTouchEvent();
  2. 对mFirstTouchTarget中的childView执行dispatchTransformedTouchEvent();

dispatchTransformedTouchEvent分析:

貌似就两种可能:
case 1: handled = super.dispatchTouchEvent(event);
case 2: handled = child.dispatchTouchEvent(event);