Touch事件分发学习笔记

窗口是Activity的容器

窗口(Window)接收用户的点击事件并逐步向内层传递,即Window->Activity->ViewGroup->...->View

dispatchTouchEvent、onInterceptTouchEvent与onTouchEvent

  • dispatchTouchEvent负责事件分发,即事件由外向内传递事件的方法
  • onInterceptTouchEvent是交给ViewGroup判断是否决定需要拦截事件(不让它的子View获取事件)的方法
  • onTouchEvent是View(或ViewGroup)自身消费事件的方法

MotionEvent

** MotionEvent**是对Touch事件的封装,MotionEvent主要包含以下事件类型:

  • ACTION_DOWN(手指按下)
  • ACTION_MOVE (手指在屏幕上移动)
  • ACTION_UP (手指离开屏幕)
  • ACTION_CANCEL (特殊事件,事件被取消,通常为被父类拦截)

dispatchTouchEvent伪源码(简化版源码)

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
37
38
39
40
41
42
43
44
45
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean handled = false;

//在ACTION_DOWN时如果子类决定不处理事件
//(即child.dispatchTouchEvent返回false)
//那么后续事件将不再继续向内传递
if (ev.actionMasked == MotionEvent.ACTION_DOWN) {
clearStatus();

if (!isDisallowIntercept && onInterceptTouchEvent(ev)) {
isSelfNeedEvent = true;
handled = onTouchEvent(ev);
} else {
handled = child.dipatchTouchEvent(ev);
if (handled) isChildNeedEvent = true;

if (!handled) {
handled = onTouchEvent(ev);
if (handled) isSelfNeedEvent = true;
}
}
} else {
if (isSelfNeedEvent) {
handled = onTouchEvent(ev);
} else {
if (!isDisallowIntercept && onInterceptTouchEvent(ev)) {
isSelfNeedEvent = true;

boolean cancel = MotionEvent.obtain(ev);
cancel.action = MotionEvent.ACTION_CANCEL;
handled = child.dispatchTouchEvent(cancel);
cancel.recycle();
} else {
handled = child.dispatchTouchEvent(ev);
}
}
}

if(ev.actionMasked == MotionEvent.ACTION_UP
|| ev.actionMasked == MotionEvent.ACTION_CANCEL) {
clearStatus();
}

return handled;
}

isDisallowIntercept是ViewGroup的一个成员变量,在子类调用父类的requestDisallowInterceptTouchEvent方法时会改变它的值。

onInterceptTouchEvent和requestDisallowInterceptTouchEvent

requestDisallowInterceptTouchEvent是子类在必要的时候用来告诉父类要不要拦截事件的方法。并且onInterceptTouchEvent会逐层向外传递。