一些疑问:
- dispatchTouchEvent,onTouchEvent,OnTouchListener.onTouch之间的关系
- 事件分发流程
- 父控件如何拦截事件
- 嵌套滑动原理
主要内容
- Activity 事件分发
- View事件分发
- ViewGroup 事件分发
- NestedScrolling机制
Activity 事件分发
对于Activity的事件分发比较简单,只要搞清楚dispatchTouchEvent方法的调用关系,如何将事件传递到DecorView
image
View 事件分发
严格的讲View的dispatchTouchEvent不算事件分发,因为View没有子View,只能说是对事件处理流程
View.dispatchTouchEvent(MotionEvent event)
- 先调用mOnTouchListener.onTouch方法(如果设置了OnTouchListener)
- 如果上面onTouch方法返回true,说明事件被消耗,处理结束,返回true
- 如果第一步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方法
网友评论