谈到View事件分发,相信大家都不陌生,我也自己琢磨了一下事件分发机制,从源码分析,提取了关键的步骤,并做小小的总结。
主要相关的类与方法为:
ViewGroup:
dispatchTouchEvent()
onInterceptTouchEvent()
onTouchEvent()
View:
dispatchTouchEvent()
onTouchEvent()
整体的思想可以概括为:
public boolean dispatchTouchEvent(){
boolean consume = false;
if(onInterceptTouchEvent()){
cousume = onTouchEvent();
}else{
consume = child.dispatchTouchEvent();
}
return consume;
}
先看整体流程图:
修正补充@2016年6月27日:
经@wangmengdeboke 的指出,左下角部分的图需要做点改动,如下图所示:
正如补充的,这个disable状态也是蛮重要的,非常感谢@wangmengdeboke的指正。
- activity事件分发
在图的左上角,是activity的事件分发,实际是调用DecorView的dispatchTouchEvent来进行的,而DecorView是继承自FrameLayout的类,其实算是最外层的viewGroup,当事件传递到viewGroup,就进入到右边分支判断。 - ViewGroup的事件分发
一般情况下,如果不对onInterceptTouchEvent与disallowIntercept进行处理,就会对viewGroup中的childView进行处理,所以这里可以通过人为干预达到拦截事件分发的效果,但值得注意的是不能够拦截down事件,因为一旦拦截,则在onInterceptTouchEvent中不会接收到up与move事件,即这些事件直接被该viewGroup处理了。 - View的事件分发
当事件分发到view后,会按序执行onTouch,onTouchEvent,onClick【如果有的话】,一旦有一者返回true消耗掉事件,则后者都不会响应,这里的onTouchEvent,适合做相关的事件处理与执行工作。
总结:
每个手指的动作,都会触发down,up,move的操作,并引发一系列的事件分发,而且一旦拦截掉down,则所有的事件也会交由该控件处理。在自定义viewGroup与View中,我们可以在onTouchEvent里面对相关的手指动作做处理,而在ViewGroup中,可以根据需要在onInterceptTouchEvent拦截该拦截需要拦截的事件。在View中,也可以修改父容器disallowInterceptTouchEvent的值达到控制父容器事件分发的目的,不过需要注意的是,down事件一定注意不要被父容器拦截到。