没有从源码角度分析,也没有图。
ViewGroup默认不拦截事件,事件优先分发给子View,子View默认不消费事件,子View没消费就代表没分发成功,ViewGroup默认也不处理,子View和自己都没消费说明没分成功,所以对于Activity来说这个事件没人消费,后续事件也不再分发。
子View默认不消费,如果消费了,返回true,那么默认情况下dispatchTouchEvent也返回true,ViewGroup也觉得分发成功了,不再需要自己消费了,也就不会再调用自己的onTouchEvent。如果手贱修改子View的分发dispatchTouchEvent返回值为false,那父View也觉得没发成功,会调用自己的onTouchEvent来处理。
这里总结就是,在没有拦截的情况下,事件是否被消费由onTouchEvent返回值决定,分发是否成功(默认情况下dispatchTouchEvent的返回值)由子View和自己是否消费了事件来决定,并且通过dispatchTouchEvent返回值告诉上级ViewGroup自己是否处理了事件,ViewGroup再根据dispatchTouchEvent返回值决定是否要由自己来消费这个事件以及后续事件还要不要分发。
从子View的角度来说,我们通过修改onTouchEvent的返回值来确定子View是否消费了这个事件,消费了就代表成功分发给了自己,默认情况dispatchTouchEvent返回值和onTouchEvent一致,而dispatchTouchEvent返回值才是真正告诉上级ViewGroup自己是否已经处理了这个事件,后续事件正常还应该交给自己来处理。
从ViewGroup的角度来说,子View告诉我它处理了,我就不再处理了,后续也交给它处理;如果子View没有处理,我就自己处理,这个时候我就像View一样了。这和没有子View一样,事件也只能分发给自己,自己就相当于View。
另一个特殊情况,View在收到上级ViewGroup分发来的事件后自己不分发而直接返回true,也就是不调用super的dispatchTouchEvent,那么View自己也获取不到事件,但有机会分发或处理后续事件。
如果父ViewGroup拦截了事件,那么事件只能分发给自己,对于当前事件的处理就和普通View一样。如果Down事件没有拦截,而拦截了Up事件,Up事件就会交给自己处理,子View会收到一个Cancel的事件。这个时候子View的dispatchTouchEvent返回值也不再重要。也是就是说,ViewGroup只在Move或Up事件进行拦截,子View可以并且只可以收到一个Cancel事件,但是即使dispatchTouchEvent返回true来告诉ViewGroup它想处理后续事件,也不会再分发给它。这个返回值在一种情况下会被父ViewGroup注意到,父ViewGroup没有拦截,但是父ViewGroup的父ViewGroup对Down的后续事件进行了拦截,那么那个子View会收到Cancel事件,onTouchEvent在收到Cancel后的返回值决定了自己dispatchTouchEvent的返回值,进一步决定了父ViewGroup的dispatchTouchEvent方法分发Cancel事件时的返回值。
最后总结一下事件分发:
收到事件后通过dispatchTouchEvent方法进行分发,如果是ViewGroup的话,会由onInterceptTouchEvent返回值决定是否拦截,不拦截(false),那么事件先分发给子View,拦截(true),事件分发给自己。如果是View,那么事件只能分发给自己。分发给自己后,调用onTouchEvent来处理事件,onTouchEvent方法的返回值意义是事件是否已处理,通常进一步确定了dispatchTouchEvent的返回值。View的dispatchTouchEvent的返回值默认情况下通常就是onTouchEvent的返回值,而ViewGroup的onTouchEvent的返回值要看子View的dispatchTouchEvent和自己的onTouchEvent返回值的情况。dispatchTouchEvent的返回值就是向上级ViewGroup反馈事件是否已经被处理,不管是分发下去被子View处理了还是自己消费了。上级ViewGroup通常也是根据子View的dispatchTouchEvent返回值来决定后续事件是否继续向下分发。
特殊情况,如果View收到一个Down事件,如果上级ViewGroup拦截后续事件,那么View会收到一个Cancel,如果是在手指未离开屏幕但移出View的范围,View在手指离开范围时会收到一个Up事件,而不是Cancel事件。