事件的分发过程由三个主要的方法来共同完成:dispatchTouchEvent(MotionEvent ev),onInterceptTouchEvent(MotionEvent ev),onTouchEvent(MotionEvent ev),来看看他们分别有什么功能
public boolean dispatchTouchEvent(MotionEvent ev)
事件的分发就是通过这个方法来执行的,只要事件传递到了某个view,那个这个view的dispatchTouchEvent方法就一定会执行,返回值收当前view的onTouchEvent方法和子元素的dispatchTouchEvent影响,表示是否消耗当前事件。
public boolean onInterceptTouchEvent(MotionEvent ev)
在dispatchTouchEvent方法里面被调用,用来判断是否拦截事件,如果当前view拦截了某个事件,那么在同一个事件序列当中,这个方法不会被再次调用,返回值表示是否拦截事件。
public boolean onTouchEvent(MotionEvent ev)
在dispatchTouchEvent方法里面被调用,用来处理点击事件,返回值表示是否消耗当前事件,如果不消耗,那么在同一个事件序列当中,当前view无法再次接收到事件。
三个方法的关系可以用以下伪代码表示:
public boolean dispatchTouchEvent(MotionEvent ev){
boolean consume = false;
if(onInterceptTouchEvent(ev)){
consume = onTouchEvent(ev);
}else {
consume = child.dispatchTouchEvent(ev);
}
return consume;
}
通过上面的伪代码,我们可以看出,对于一个viewgroup来说,一个事件产生,首先它的dispatchTouchEvent方法会调用,然后会执行它的onInterceptTouchEvent方法,如果onInterceptTouchEvent返回true,表示要拦截事件,则viewgroup的onTouchEvent方法会被调用,如果不拦截,viewgroup的子元素会接着调用dispatchTouchEvent方法。如果一个view需要消耗事件并且设置了onTouchListener,那么会执行onTouch方法,如果onTouch方法返回true,则不会调用onTouchEvent方法。返回false,则会调用。我们熟悉的onClick方法就是在onTouchEvent调用,也就是说如果设置了ontouchListener,就不会调用onClick方法。
总结一下
1:当一个事件产生,首先会传递给activity,activity再传递给window,最后由window传递给顶级view。然后按正常事件分发开始传递。如果子元素的onTouchEvent方法返回了false,也就是不处理事件,则会调用父容器的onTouchEvent。若果都不进行处理,最终会返回给activity,也就是activity的onTouchEvent方法被调用。就好比上级给下级分配任务,下级如果没有处理只能由上级再来处理。上级如果也没有处理,只能又更高级别的来处理。其中activity就相当于最高领导。
2:同一个事件序列是指手机触摸屏幕开始,直到离开屏幕结束。
3:一个事件序列只能被一个view拦截消耗,因为一旦一个元素拦截了此事件,那么同一事件序列内所有的事件都会交给它处理,,并且它的onInterceptTouchEvent方法不会再被调用,因为已经交由它处理,不需要在询问是否拦截了。因此同一事件序列的事件不会有两个view同时处理。除非在某个view的ontouch
event方法里把事件强行传递给别的view处理。
4:viewgroup默认不拦截任何事件。也就是onInterceptTouchEvent返回false。
5:view(排除viewgroup)因为不存在子元素,所以也没有onInterceptTouchEvent方法,一旦有事件传递给它,那么它的onTouchEvent方法就会被调用
6:view的onTouchEvent默认都会消耗事件,除非它是不可点击的
7:子元素可以通过requestDisallowInterceptTouchEvent方法干预父元素的事件分发,但是Down事件除外。