View的事件分发机制
事件分发机制是View事件体系中的核心知识点,View的滑动冲突问题的解决方法就是基于View的分发机制,因此理解掌握View的分发机制是十分重要的。
1.事件的传递规则
《View的事件体系——View的基础知识》一文中我们已经介绍了MotionEvent,即手指触碰屏幕后所产生的一系列事件。
所谓的事件分发机制实质就是对MotionEvent事件的分发过程
,也就是说当一个MotionEvent产生后,系统需要把这个事件传递到一个具体的View处理,而这个过程就称为分发过程。
View的事件分发主要是由3个函数决定:dispatchTouchEvent
、 onInterceptTouchEvent
以及 onTouchEvent
。
当一个MotionEvent事件产生时,如果事件坐标处于ViewGroup
所“管辖范围”,首先调用的是该ViewGroup
的dispatchTouchEvent
方法,而dispatchTouchEvent
方法内部调用onInterceptTouchEvent
方法,其作用是判断是否拦截该事件,如果拦截,则调用ViewGroup
的onTouchEvent
处理这个事件,否则调用子View
的dispatchTouchEvent
方法,如此反复直到这个事件被处理。
我们可以用下列伪代码
表示这一过程(非源码):
//ViewGroup的dispatchTouchEvent方法
public boolean dispatchTouchEvent(MotionEvent event){
boolean consume=false;
if(onInterceptTouchEvent(event)){
consume=onTouchEvent(event);//如果拦截就调用onTouchEvent处理点击事件
}else {
consume=child.dispatchTouchEvent(event);//如果不拦截就将点击事件分发给子View
}
return consume;
}
也可以用下方流程图表示这一过程:
上面的简述中并没有考虑子View选择不处理该事件的情况,即子View的onTouchEvent返回了false,这种情况成为事件回传,后文会介绍。
ViewGroup的onInterceptTouchEvent方法返回值决定了该ViewGroup是否拦截此事件,
返回true
时,表示拦截事件
,那么紧接着就会调用ViewGroup的onTouchEvent方法
.
返回false
时,表示不拦截事件
,那么就会将该系列事件交给子View处理
。
注意,View的事件体系中,从down->move->……->move->up,这一个过程为同一个事件系列,如果某一事件在ViewGroup的onInterceptTouchEvent中返回false,那么该事件后所有属于该事件系列的事件都不会再交给该ViewGroup的onTouchEvent。
当一个点击事件产生后,它的传递过程遵循如下顺序:
Activity->Window->View。即Activity最先拿到事件对象,Activity把事件对象传递给PhoneWindow,PhoneWindow再传递给DecorView,DecorView通过遍历再传递到我们的ViewGroup。
2.onTouch、onTouchEvent、onClick优先级
当一个View处理触摸事件时,同时设置了onTouchListener
(内含onTouch抽象方法
)和onClickListener
(内含onClick抽象方法
)