触摸流程

window的最底层的View就是DecorView,那么这个时候调用的应该就是DecorView的dispatchTouchEvent方法

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
  final Window.Callback cb = mWindow.getCallback();
  return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
          ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}

callBack是谁?,在Activity的attach方法中,

mWindow.setCallback(this);

这个callback就是activity本身,所以我们要去Activity中查看它的dispatchTouchEvent方法

public boolean dispatchTouchEvent(MotionEvent ev) {
  if (ev.getAction() == MotionEvent.ACTION_DOWN) {
      onUserInteraction();
  }
  if (getWindow().superDispatchTouchEvent(ev)) {
      return true;
  }
  return onTouchEvent(ev);
}

也就是activity会先将事件交给DecorView去处理,如果被消耗掉,就返回true。如果没有消耗这个事件,就回调Activity自己的onTouchEvent。

总结

那么把上面的一大坨我们简略的来讲如下的流程:

用户触摸屏幕产生设备节点中断并保存到/dev/input/目录下
底层的EventHub监听目录,将事件读出并加工返回给随着WMS一起启动的底层的InputReader
InputReader处理加工之后交给InputDispatcher来进行分发,通过socket通知UI进程的InputEventReceiver接收到事件
InputEventReceiver将回调事件一步步传递给Activity来进行分发
Activity先将事件交给DecorView来进行处理,如果DecorView消耗则返回true,否则自己回调onTouchEvent方法

View中dispatchTouchEvent分析

 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;
        }

以上代码可看出四个条件只要有一个不满足就会调用onTouchEvent事件


触摸流程_第1张图片
image.png

结论
onTouch优先于onTouchEvent执行。

如果在onTouch方法中通过返回true将事件消费掉,onTouchEvent将不会再执行。

onTouch能够得到执行需要两个前提条件

  1. mOnTouchListener的值不能为空。
  2. 当前点击的控件必须是enable的。
    因此如果你有一个控件是非enable的,那么给它注册onTouch事件将永远得不到执行。对于这一类控件,如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实现。

ViewGroup

首先判断是否拦截
如果是按下事件,在允许拦截的情况下,调用onInterceptTouchEvent判断是否拦截
如果不是按下事件,直接拦截

// 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;
            }

拦截

然后根据按下的坐标位置筛选出可以接受该点击事件的子View,并按照Z轴进行排序
源码中的英文为
// Find a child that can receive the event.
// Scan children from front to back.
然后遍历这些筛选出来的子View
调用

dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)

不拦截

调用

handled = dispatchTransformedTouchEvent(ev, canceled, null,
                        TouchTarget.ALL_POINTER_IDS);

在dispatchTransformedTouchEvent函数中,如果子View(child)不为null,调用子View的dispatchTouchEvent
否则就调用自身View的dispatchTouchEvent

 private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
            View child, int desiredPointerIdBits) {
            final boolean handled;
            if (child == null) {
                handled = super.dispatchTouchEvent(event);
            } else {
                handled = child.dispatchTouchEvent(event);
            }
            event.setAction(oldAction);
            return handled;
        }
        ......
}

你可能感兴趣的:(触摸流程)