android事件傳遞機制測試分析
來自: http://www.jcodecraeer.com//a/anzhuokaifa/androidkaifa/2016/0226/4002.html
情景:activity-viewGroup-|ChildViewUp(ChildUp)(疊在上面的view)
|ChildViewDown(ChildDown)(疊在下面的view)
注:
1、以下事件如果不特指均為onTouchEvent
2、如果onTouchListener沒有設置,onTouchEvent是事件真正處理和消費的位置
3、該情景用于描述事件傳遞的基本單元,更加復雜的結構都可以由該情景組成
4、以下說的'傳遞給XXX'值的是事件傳遞給該view的onTouchEvent方法中
5、所有的ACTION_DOWN事件都會經過viewgroup的onInterceptTouchEvent方法
6、如果ChildView消費了ACTION_DOWN事件,所有后續事件仍然會經過該viewgroup的onInterceptTouchEvent方法
7、如果viewgroup消費了ACTION_DOWN事件,所有后續事件不會經過該viewgroup的onInterceptTouchEvent方法
8、所有事件都是由dispatchTouchEvent方法發起傳遞的
假設一、viewGroup的onInterceptTouchEvent返回false(即父布局不攔截事件)
1、如果一個View不消費ACTION_DOWN事件,那么該View最多只會接收到ACTION_DOWN事件
2、如果一個View消費了ACTION_DOWN事件,該view將處理所有事件
3、當一個ACTION_DOWN事件到來,ViewGroup會遍歷其ChildView,將事件從上層ChildView依次傳遞給下層ChildView,當有一個ChildView消費了ACTION_DOWN事件,往后的事件都會交由該ChildView處理,同時ChildView的遍歷也會結束.
4、如果該ChildView消費了ACTION_DOWN事件,剩余的事件不管該childView消費與否都會先傳遞給viewgrou的onInterceptTouchEvent方法,再傳遞給該ChildView,如果該ChildVeiw不消費剩余這些事件(ACTION_MOVE等),那么這些事件會交給activity處理,并且activity消費不消費都沒有所謂
5、如果沒有ChildView愿意消費ACTION_DOWN事件,那么該ACTION_DOWN事件會傳遞給Viewgroup,如果viewgroup消費了ACTION_DOWN事件,后續事件(ACTION_MOVE等)不管消費與否,都會傳遞過來,如果viewgroup不消費后續事件,同樣最后會傳遞給activity(如果viewgroup上面還有viewgroup,后續事件同樣會先經由上級viewgroup的onInterceptEvent方法)
假設二、viewGroup的onInterceptTouchEvent將返回true(即父布局要攔截事件)
1、建立在假設一的基礎之上
2、如果viewgroup攔截了ACTION_DOWN事件(onInterceptTouchEvent中在ACTION_DOWN事件返回true,以下同理),但viewgroup不消費該事件,onInterceptTouchEvent方法在該后續事件中不再調用,后續事件不管消費與否都會交給上一級(這里就是activity)處理,如果viewgroup消費ACTION_DOWN事件,后續事件都會交由viewgroup處理,如果viewgroup不消費后續事件,則會交給activity處理
3、如果viewgroup不攔截ACTION_DOWN事件,且某childView消費了ACTION_DOWN事件(這意味后續事件將交給該childView處理),但是viewgroup攔截了ACTION_MOVE,該ChildView將失去處理后續事件的權利,獲得一個ACTION_CANCEL事件,然后該事件的消費權轉移給其viewgroup.
4、如果viewgroup不攔截ACTION_DOWN事件,但又攔截了ACTION_UP事件,雖然該事件會傳遞給onInterceptTouchEvent方法,但不會傳遞到viewgroup
測試對照:
1、都不消費事件
全部接收到action-down事件,后續事件全部由activity接收處理
事件流程
(ACTION-DOWN)viewGroup(onInterceptTouchEvent)-childUp-childDown-viewGroup-activity(ACTION-MOVEACTION-UP)activity
2、viewGroup只消費action-down事件
除activity外全部接收到action-down事件,后續事件全部由viewgroup和activity接收處理
事件流程
(ACTION-DOWN)viewGroup(onInterceptTouchEvent)-childUp-childDown-viewGroup-activity
(ACTION-MOVE)viewGroup-activity
(ACTION-UP)viewGroup-activity
3、viewGroup只消費action-move事件
結果同(1)并且viewGroup沒有收到action-move事件
4、viewGroup只消費action-up事件
結果同(1)并且viewGroup沒有收到action-up事件
5、viewGroup同時消費action-down和action-move事件
除activity外全部接收到action-down事件,接著只有viewGroup接收到action-move事件,最后viewgroup和activity先后收到action-up事件
事件流程
(ACTION-DOWN)viewGroup(onInterceptTouchEvent)-childUp-childDown-viewGroup-activity
(ACTION-MOVE)viewGroup
(ACTION-UP)viewGroup-activity
6、viewGroup同時消費action-down和action-up事件
除activity外全部接收到action-down事件,接著activity和viewGroup收到action-move事件,最后只有viewGroup接收到action-up事件
(ACTION-DOWN)viewGroup(onInterceptTouchEvent)-childUp-childDown-viewGroup-activity
(ACTION-MOVE)viewGroup-activity
(ACTION-UP)viewGroup
7、ChildViewUp消費actionDown事件
事件流程
(ACTION-DOWN)viewGroup(onInterceptTouchEvent)-childUp
(ACTION-MOVE)viewGroup(onInterceptTouchEvent)-childUp-activity
(ACTION-UP)viewGroup(onInterceptTouchEvent)-childUp-activity
8、ChildViewDown消費actionDown事件
事件流程
(ACTION-DOWN)viewGroup(onInterceptTouchEvent)-childUp-childDown
(ACTION-MOVE)viewGroup(onInterceptTouchEvent)-childDown-activity
(ACTION-UP)viewGroup(onInterceptTouchEvent)-childDown-activity
9、ChildViewUp消費actionDown和actionMove事件
事件流程
(ACTION-DOWN)viewGroup(onInterceptTouchEvent)-childUp
(ACTION-MOVE)viewGroup(onInterceptTouchEvent)-childUp
(ACTION-UP)viewGroup(onInterceptTouchEvent)-childUp-activity
10、ChildViewUp消費所有事件,Viewgroup的onInterceptTouchEvent方法攔截actionDown事件
事件流程
(ACTION-DOWN)viewGroup(onInterceptTouchEvent)-viewGroup(onTouchEvent)-activity
(ACTION-MOVE)activity
(ACTION-UP)activity
11、ChildViewUp消費所有事件,ViewGroup的onInterceptTouchEvent方法攔截actionMove事件
事件流程
(ACTION-DOWN)viewGroup(onInterceptTouchEvent)-childUp
(ACTION-CANCEL)childUp
(ACTION-MOVE)activity
后面的n個move交由viewgroup處理
(ACTION-UP)viewgroup(onTouchEvent)-activity
childUp消費了actiondown事件,因此后續的事件本來應該交由childUp處理,但其父布局將ACTION_MOVE事件攔截了,所以該事件序列交由其父布局處理,childUp被傳遞了一個ACTION_CANCEL以結束事件序列的處理
12、ChildViewUp消費所有事件,ViewGroup的onInterceptTouchEvent方法攔截ACTION_UP事件
事件流程
(ACTION-DOWN)viewGroup(onInterceptTouchEvent)-childUp
(ACTION-MOVE)viewGroup(onInterceptTouchEvent)-childUp
(ACTION-UP)viewGroup(onInterceptTouchEvent)-childUp
ACTION_UP事件不會被攔截(會經過onInterceptTouchEvent方法)
總結:
所有事件都是從dispatchTouchEvent開始的,不同點在于,有些view是viewgroup,有些就是view。如果該view是viewgroup,需要考慮其對事件的攔截和對子view的事件傳遞,一個view消費了事件(事件能傳遞給它),如果不考慮攔截,那么后續的事件都會傳遞給它,考慮攔截,攔截后事件處理權交給viewgroup這個view(相當于viewgroup消費了ACTION_DOWN),如果沒有view消費事件(ACTION_DOWN),activity消費之。