Android View 事件传递

一、关注三个方法

• dispatchTouchEvent(MotionEvent et)

该方法用于传递事件(存在于View,Activity),返回值由当前ViewonTouchEvent()方法和 下级ViewdispatchTouchEvent()决定,表示是否消费当前事件。true表示当前View需要后续事件,后续事件(比如ACTION_DOWN之后的ACTION_MOVE) 会继续传进来,否则无法再接收到后续事件。

• onIntercepTouchEvent(MotionEvent et)

该方法用于拦截事件(存在于ViewGroup),返回结果表示是否拦截当前事件。true表示当前ViewGroup对事件进行了拦截,事件不会继续向下传递,否则事件会继续分发。在一个事件序列中,如果拦截了一次事件,那么以后此事件序列中的事件都不会再次调用该方法。发。

• onTouchEvent(MotionEvent et)

用于消费事件(存在于View,Activity),返回值表示当前View是否消费了当前事件,如果没有消耗,当前View无法接收同一事件序列中的其他事件。

注意:以上三个方法的参数都是一个MotionEvent类型的参数,该类型的对象包含了触摸的各种属性(包括触发时间、位置等信息)

二、关注事件传递流程

1、传递顺序:Activity->Window->View

2、起始点是Activity. dispatchTouchEvent()

3、如果事件到达ViewGroup时,该ViewGroupdispatchTouchEvent()被调用,此时会进行一系列的判断,首先会调用onInterceptTouchEvent()判断当前ViewGroup是否对事件进行拦截,如拦截则会继续调用当前ViewGrouponTouchEvent()方法处理这个事件,并且拦截后事件不会继续向下分发。若未拦截,则会继续调用子View/ViewGroupdispatchTouchEvent()方法进行事件分发。

4、 如果事件到达View,类似以上说明的过程,不过此时View没有onInterceptTouchEvent()方法,所以View. dispatchTouchEvent()分发事件时直接调用当前ViewonTouchEvent()处理事件,View. onTouchEvent()的结果会作为View. dispatchTouchEvent()的返回值返回,此时View. dispatchTouchEvent()的返回值就是父级ViewGroup. dispatchTouchEvent()方法的返回值,如此直到返回到Activity. dispatchTouchEvent()

接着看看几种情况:

a. 当所有的View/ViewGroup都不消费事件情况:

打印得到日志记录:

事件流程图:

总结:可以看出,事件传递是一级一级往下传递,当到达最后一个子View的时候,若该子View不对其进行消费,那么事件又会一级一级的往回传递,直至ActivityonTouchEvent();对于接下来的该事件系列中的其他事件,就不会再分发给那些不需要消费事件的View,而是由消费ACTION_DOWN事件的View直接继续消费这些事件。

b. ViewGroup对事件进行拦截并消费:

打印得到日志记录:

事件流程图:

总结:当ViewGroup对事件进行拦截并消费,事件到此ViewGroup截止不往下分发。此时ViewGroup.onInterceptTouchEvent()返回true,该事件系列中的其他事件到来的时候,onInterceptTouchEvent()方法不会再调用,而是直接由该ViewGrouponTouchEvent()方法消费事件。

c. ViewGroup对事件进行拦截但不消费

打印得到日志记录:

事件流程图:

总结:与上一种情况类似,事件也是到此ViewGroup截止不往下分发。但是此处ViewGroup并未对事件进行消费,所以事件会往回传递直至消费。因为ViewGroup并未对事件进行消费,所以事件系列中的其他事件不会再传递到此ViewGroup,而是由消费ACTION_DOWN事件的View直接继续消费这些事件。

d. ViewGroup. dispatchTouchEvent()返回false

打印得到日志记录:

事件流程图:

总结:此种情况下,表示ViewGroup不消耗当前事件,所以事件往回传递直至消费;该事件系列中的其他事件也不会再传递进来,而是由消费ACTION_DOWN事件的View直接继续消费这些事件。

e. ViewGroup. dispatchTouchEvent()返回true

打印得到日志记录:

事件流程图:

总结:与上一种情况相反,dispatchTouchEvent()返回true表示消费当前事件,所以当前ViewGroup会一直消费该事件系列中的事件。

f. View消费事件

打印得到日志记录:

事件流程图:

总结:这种情况是最常见的View消费事件的情况(例如点击Button),事件一级级往下传递直至目标View消费事件。

g. View仅消费ACTION_DOWN事件

打印得到日志记录:

事件流程图:

总结:此处的情况有些特殊,View只消费了ACTION_DOWN事件,当该事件系列中的其他事件到来的时候不要View消费这些事件(返回false),此时父元素的onTouchEvent()方法并不会调用。当前View接下来可以持续收到该事件系列中的其他事件,最后这些未被消费的事件由Activity处理。

最后对于多点触摸,有点类似以上分析的单点触摸的情形。但是多了ACTION_POINTER_DOWNACTION_POINTER_UP。调用顺序如下:

ACTION_DOWN—> ACTION_POINTER_DOWN—> ACTION_MOVE—> ACTION_POINTER_UP—> ACTION_UP

参考:

共技术点之 View 事件传递

Android开发艺术探索》