回顾
- 在回顾概念篇中,我们已经知道了Android中的事件对应一个MotionEvent对象。事件的分发机制其实就是对MotionEvent对象的传递,直到MotionEvent对象传递到具体的View为止。
事件分发核心方法
- MotionEvent事件对象经过三个核心方法共同完成,才可以传递到我们所期望的View上,三个核心方法分别是:
- dispatchTouchEvent(MotionEvent me)
- onInterceptTouchEvent(MotionEvent me)
- onTouchEvent(MotionEvent me)
dispatchTouchEvent(MotionEvent me)
- 该方法用来进行事件的分发,一旦事件对象到了当前View上,边会去执行该方法,该方法用来对事件对象进行分发,用来决定是自己处理呢?还是交给下级处理。
- 该方法的返回值会受到当前View的onTouchEvent(...)方法,也会受到下级View的dispatchTouchEvent(...)方法的影响
onInterceptTouchEvent(MotionEvent me)
- 顾名思义,该方法用来判断在MotionEvent对象的传递过程中,是否要拦截该对象,一旦拦截该事件对象,则会去执行onTouchEvent(..)方法去响应事件,也就是自己处理。如果不拦截,事件对象会依次向下传递
onTouchEvent(MotionEvent me)
- 该方法可以理解成事件处理程序。当该方法返回值为true的时候,表示消费此事件,那么之后的事件序列边会直接传递到这里进行事件处理。如果返回值为false,之后的事件序列就不会在传递到该方法中了。
核心方法之间的关系
// 事件分发
public boolean dispatchTouchEvent(MotionEvent me){
boolean consume=false;
// 如果拦截事件对象
if(onInterceptTouchEvent(ev)){
// 调用onTouchEvent(ev)进行处理
consume=onTouchEvent(ev);
}else{
// 向下分发
consume=child.dispatchTouchEvent(ev);
}
return consume
}
流程梳理
- 当一个点击事件产生,系统会封装出一个MotionEvent对象。该对象会先到Activity中,由Activity传递到Window中,再由Window传递到DecorView,最后由DecorView传递到我们所写的View中。
- Activity -> Window -> DecorView ->我们的View
- 当事件对象传递到我们的View中时,就要开始分情况讨论了,因为ViewGroup和View在上述三个核心方法中略有区别,也就是当事件对象传递给他们时,他们会有不同的反应
ViewGroup如何处理事件
- 当事件传递到ViewGroup后,dispatchTouchEvent(me)被调用,如果onInterceptTouchEvent(me)返回true,表示拦截事件,那么就会去执行onTouchEvent(me)方法,如果不拦截事件,则开始进行事件分发。这里仅仅分发到一级子类。所谓的一级子类指的是只有一层继承关系。比如如下关系:
- LinearLayout -> RelativeLayout -> Button
- 如果事件到了LinearLayout,那么LinearLayout的dispatchTouchEvent只负责分发事件到RelativeLayout,并不是也会分到Button中,事件分发到Button,是RelativeLayout要做的事。
- 五大布局(ViewGroup的子类)默认的onInterceptTouchEvent(me)返回为false,也就是不拦截事件。你想要的拦截的话需要继承重写五大布局。
View如何处理事件
- 当事件传递到View后,会先去判断是否设置了onTouchListener()事件,如果设置了则会去调用onTouch()方法,如果方法返回true,表示消耗了此事件,那么onTouchEvent()就不会调用。如果方法返回false,才会去执行onTouchEvent()事件。如果执行到了onTouchEvent()方法,View还有点击事件的话,通过调用super.onTouchEvent(me)方法还回去执行onClick事件,View中这三个事件处理程序优先级如下:
- onTouchListener -> onTouchEvent -> onClickListener
事件响应
- 但事件分达到最顶层的View,则开始依次向上执行onTouchEvent(me)方法,如果底层View的该方法返回false,那么上层View的onTouchEvent(me)方法会被调用,以此类推,如果所有view的该方法都不返回true,则会交给Activity的onTouchEvent(me)的方法执行