1. 形式
Touch 事件被封装成 MotionEvent 对象来传递。
由 ACTION_DOWN 开始,经过若干次 ACTION_MOVE 并以 ACTION_UP 结束的一个事件序列称为一个 gesture。
2. 角色
涉及 Touch 事件处理的角色有四种:
- Activity
- Window
- ViewGroup
- View
3. 基本流程
事件在 activity 中的分发起始于 dispatchTouchEvent()
方法。从源码可以看出 activity 调用了 Window 的 superDispatchTouchEvent()
方法来处理,若返回值为 true,则结束事件分发,否则调用 onTouchEvent()
方法。
1 2 3 4 5 6 7 8 9
| public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } if (getWindow().superDispatchTouchEvent(ev)) { return true; } return onTouchEvent(ev); }
|
Window 的实现类为 PhoneWindow,PhoneWindow 实际调用了 DecorView 的 superDispatchTouchEvent()
。
而 DecorView 是 activity 中的顶级 View,它其实是一个 FrameLayout,它的 superDispatchTouchEvent()
直接调用了 ViewGroup 的 dispatchTouchEvent()
。
由此,事件流入 View 层级。
1 2 3 4 5 6 7 8 9
| @Override public boolean superDispatchTouchEvent(MotionEvent event) { return mDecor.superDispatchTouchEvent(event); }
public boolean superDispatchTouchEvent(MotionEvent event) { return super.dispatchTouchEvent(event); }
|
4. ViewGroup dispatchTouchEvent()
流程
事件流入 View 层级后会逐级分发,ViewGroup 处在事件分发的中间层,是事件分发机制中最复杂的部分。此处源码非常长,就不贴出来了。
ACTION_DOWN 事件作为一次 gesture 的开始,可以影响后续事件的传递流程。为了方便理解,这里将它与其他类型的事件分开分析。
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
| @Override public boolean dispatchTouchEvent(MotionEvent ev) { boolean handled = false; final boolean intercepted; if (!disallowIntercept) { intercepted = onInterceptTouchEvent(ev); ev.setAction(action); } else { intercepted = false; } if (!intercepted && mChildrenCount != 0) { for (View child : mChildren) { if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null)) { continue; } if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { handled = true; } } } else { handled = super.dispatchTouchEvent(event); } return handled; }
|
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
| @Override public boolean dispatchTouchEvent(MotionEvent ev) { boolean handled = false; final boolean intercepted; if (!disallowIntercept) { intercepted = onInterceptTouchEvent(ev); ev.setAction(action); } else { intercepted = false; } if (!intercepted && mChildrenCount != 0) { for (View child : children) { if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { handled = true; } } } else { handled = super.dispatchTouchEvent(event); } return handled; }
|
5. View dispatchTouchEvent()
流程
View 位于事件分发的最下层,不再向下分发。View 的事件分发逻辑大致等效于 return mOnTouchListener.onTouch(this, e) || onTouchEvent(e);
。
View 的 OnClickListener 是在 onTouchEvent()
方法里回调的,所以如果我们为 View 设置了 onTouchListener 并在 onTouch()
里返回 true,那么它的 OnClick 等系统预设的事件会失效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public boolean dispatchTouchEvent(MotionEvent event) { boolean result = false;
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; } return result; }
|