沒有從源碼角度分析,也沒有圖。
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事件。