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
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容