关于事件分发,关键是要理清楚三个方法的关系,
dispatchTouchEvent
onInterceptTouchEvent
onTouchEvent
如果没有任何View拦截处理事件,并且每个View也不处理这个事件,那么这个事件会按照如下方式流转:
事件会以父元素到子元素的顺序去传递事件,
事件会以子元素到父元素的顺序去消费事件。
是一个U型结构。
其中只有ViewGroup中有onInterceptTouchEvent,用来判断是否拦截事件。
而dispatchTouchEvent方法有点特殊,这个方法在View中和ViewGroup中实现是不一样的。ViewGroup继承自View,并且复写了这个dispatchTouchEvent方法。
View 的dispatchTouchEvent的主要功能是负责时间的消费,即调用onTouchEvent。
VIewGroup 的dispatchTouchEvent主要功能是负责事件的分发。但是当发现这个事件需要自己处理的时候,就回调用super.dispatchTouchEvent()。这个super的方法就是View中的方法实现,即开始调用onTouchEvent消费这个事件。
对于各个方法的返回值的不同,事件的流向可以参考下面这个图
一个事件流包括一个DOWN、UP和 n 个MOVE三种子事件。
这三个事件中,最重要的事件是** DOWN **事件。
当一个View处理了DOWN事件以后,系统会认为他要处理这整个事件,就回将后续的MOVE和UP事件都交由它处理。
所以DOWN事件是一个很特别的事件,。
情况一:
如果没有任何View处理这个事件,那么这个事件会传递到Activity的onTouchEvent中。
所有的事件流转过程中的方法,只会受到一个子事件:DOWN。
其他子事件在流转过程中都不会受到。
因为没有View处理DOWN事件,系统认为没有要处理这个事件的控件,后续的所有的事件都不会在流程中传递。
情况二:
如果ViewGroup处理了DOWN事件。
那么事件的流转就不会在到View,直接交给了ViewGroup去处理了,直接调用ViewGroup的onTouchEvent事件。
情况三:
View处理了DOWN事件,那么这个事件系统会交由这个View进行处理。
直接调用这个View的onTouchEvent事件去处理。
但是这个时候,ViewGroup是可以拦截MOVE和UP事件的。
如果ViewGroup选择性拦截了MOVE和UP,那么这个View就仅仅只收到GroupView没有拦截的事件,被拦截掉的MOVE和UP都会交由ViewGroup的onTouchEvent去处理。
这也是处理滑动冲突的基本思路,就是按照条件过滤MOVE事件,达到解决冲突的目的。
这里注意,当ViewGroup拦截了MOVE和UP事件后,View的ACTION_CANCEL事件会被调用。
点击事件的处理:
默认情况下,View的onTouchEvent是不处理事件的,即返回false,但是当这个View的clickable或者longClickable为true时,这个View就回默认返回true,即默认处理touch事件。
事件优先级
onTouchEvent < OnTouchListener