Android事件分发

一些疑问:

  • dispatchTouchEvent,onTouchEvent,OnTouchListener.onTouch之间的关系
  • 事件分发流程
  • 父控件如何拦截事件
  • 嵌套滑动原理

主要内容

  • Activity 事件分发
  • View事件分发
  • ViewGroup 事件分发
  • NestedScrolling机制

Activity 事件分发

对于Activity的事件分发比较简单,只要搞清楚dispatchTouchEvent方法的调用关系,如何将事件传递到DecorView


image

View 事件分发

严格的讲View的dispatchTouchEvent不算事件分发,因为View没有子View,只能说是对事件处理流程

View.dispatchTouchEvent(MotionEvent event)

  1. 先调用mOnTouchListener.onTouch方法(如果设置了OnTouchListener)
  2. 如果上面onTouch方法返回true,说明事件被消耗,处理结束,返回true
  3. 如果第一步onTouch方法返回false,或者没有设置OnTouchListener,才会调用onTouchEvent,并返回onTouchEvent的结果

整个View.dispatchTouchEvent就这么简单,下面看下onTouchEvent方法

View.onTouchEvent(MotionEvent event)

onTouchEvent主要处理了OnClickListener和OnLongClickListener

  • ACTION_DOWN:调用checkForLongClick()方法添加延迟事件
  • ACTION_MOVE:调用了removeLongPressCallback()移除长按延迟事件
  • ACTION_UP:调用performClickInternal()触发OnClickListener(前提是OnLongClickListener没有触发)

ViewGroup 事件分发

  • 首先调用onInterceptTouchEvent方法判断是否拦截事件(默认返回false不拦截),调用了requestDisallowInterceptTouchEvent()方法后也不拦截事件,如下代码:
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;
}
  • 如果不拦截事件,就遍历childView查找对应触摸位置上且可见的子View,如果找到了就调用child.dispatchTouchEvent,如果没找到或者child.dispatchTouchEvent返回false则会继续调用super.dispatchTouchEvent(event)将事件分发给自己
  • 如果拦截事件,调用super.dispatchTouchEvent(event)分发事件给自己,即从View那里继承而来的dispatchTouchEvent方法
image

你可能感兴趣的:(Android事件分发)