[关闭]
@act262 2017-05-24T14:25:42.000000Z 字数 2602 阅读 948

Android Touch事件分发

AndroidSource


触摸事件从硬件层产生,由系统分发至当前应用,再由当前应用分发到前台展示的Activity,其中Activity这一层不是必须的.

屏幕触摸 -> Activity -> Window -> RootView -> View

整个调用链中使用了责任链的设计模式,将事件一层一层往下传递,如果被下层处理了,就不会返回上层了,上层也就不需要处理了,如果下层也不处理,那么原路返回上层,让上层去处理这个事件.

Activity.java

  1. public boolean dispatchTouchEvent(MotionEvent ev) {
  2. if (ev.getAction() == MotionEvent.ACTION_DOWN) {
  3. onUserInteraction();
  4. }
  5. if (getWindow().superDispatchTouchEvent(ev)) {
  6. return true;
  7. }
  8. // 下层没有消费掉事件,则交给自己的onTouchEvent处理
  9. return onTouchEvent(ev);
  10. }
  11. public boolean onTouchEvent(MotionEvent event) {
  12. if (mWindow.shouldCloseOnTouch(this, event)) {
  13. finish();
  14. return true;
  15. }
  16. return false;
  17. }

Window.java

  1. public abstract boolean superDispatchTouchEvent(MotionEvent event);

Window的具体实现类是PhoneWindow

  1. public boolean superDispatchTouchEvent(MotionEvent event) {
  2. return mDecor.superDispatchTouchEvent(event);
  3. }

这里的mDecor是DecorView extends FrameLayoutViewGroup

  1. public boolean superDispatchTouchEvent(MotionEvent event) {
  2. return super.dispatchTouchEvent(event);
  3. }

所以流程跳转到了ViewGroup的dispatchTouchEvent方法

  1. public boolean dispatchTouchEvent(MotionEvent ev) {
  2. // ...
  3. // ViewGroup的这里需要特殊处理拦截的处理
  4. if (!disallowIntercept) {
  5. intercepted = onInterceptTouchEvent(ev);
  6. ev.setAction(action); // restore action in case it was changed
  7. } else {
  8. intercepted = false;
  9. }
  10. childView.dispatchTouchEvent();
  11. }
  12. public boolean onInterceptTouchEvent(MotionEvent ev) {
  13. if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
  14. && ev.getAction() == MotionEvent.ACTION_DOWN
  15. && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
  16. && isOnScrollbarThumb(ev.getX(), ev.getY())) {
  17. return true;
  18. }
  19. return false;
  20. }
  21. public boolean onToucheEvent(MotionEvent ev) {
  22. // 继承自View的onTouchEvent方法
  23. }

最后是到最后子节点的View来处理或者不处理

  1. public boolean dispatchTouchEvent(MotionEvent event) {
  2. // ...
  3. // 如果设置了OnTouchListener,则OnTouchListener可以优先处理
  4. ListenerInfo li = mListenerInfo;
  5. if (li != null && li.mOnTouchListener != null
  6. && (mViewFlags & ENABLED_MASK) == ENABLED
  7. && li.mOnTouchListener.onTouch(this, event)) {
  8. result = true;
  9. }
  10. // 前面的OnTouchListener没有消费掉,那么就交给自己的onTouchEvent来来处理
  11. if (!result && onTouchEvent(event)) {
  12. result = true;
  13. }
  14. }
  15. public boolean onTouchEvent(MotionEvent event) {
  16. // ... 这里对点击,长按等处理
  17. switch (action) {
  18. case MotionEvent.ACTION_UP:
  19. // ...
  20. if (mPerformClick == null) {
  21. mPerformClick = new PerformClick();
  22. }
  23. // 处理点击的情况,执行点击
  24. if (!post(mPerformClick)) {
  25. performClick();
  26. }
  27. if (mUnsetPressedState == null) {
  28. mUnsetPressedState = new UnsetPressedState();
  29. }
  30. // 点击完后变成非按压状态
  31. if (prepressed) {
  32. postDelayed(mUnsetPressedState,ViewConfiguration.getPressedStateDuration());
  33. } else if (!post(mUnsetPressedState)) {
  34. // If the post failed, unpress right now
  35. mUnsetPressedState.run();
  36. }
  37. break;
  38. case MotionEvent.ACTION_DOWN:
  39. // Not inside a scrolling container, so show the feedback right away
  40. // 变成按压状态,同时检测是否变成长按状态
  41. setPressed(true, x, y);
  42. checkForLongClick(0, x, y);
  43. // ...
  44. // 默认是没有处理的,所以会给上层有机会处理
  45. return false;
  46. }

由最底层View返回是否消费掉事件

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注