android事件传递机制测试分析

松林小鼠 9年前

来自: 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 


1456477666518059.png



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   


1456477686129387.png

1456477699113423.png


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   


1456477713989731.png

1456477721977208.png


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  


1456477734964342.png


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以结束事件序列的处理 


1456477745946268.png


12、ChildViewUp消费所有事件,ViewGroup的onInterceptTouchEvent方法拦截ACTION_UP事件

事件流程

(ACTION-DOWN)viewGroup(onInterceptTouchEvent)-childUp 

(ACTION-MOVE)viewGroup(onInterceptTouchEvent)-childUp 

(ACTION-UP)viewGroup(onInterceptTouchEvent)-childUp 

ACTION_UP事件不会被拦截(会经过onInterceptTouchEvent方法)   


1456477755749226.png

1456477765397484.png


总结: 

所有事件都是从dispatchTouchEvent开始的,不同点在于,有些view是viewgroup,有些就是view。如果该view是viewgroup,需要考虑其对事件的拦截和对子view的事件传递,一个view消费了事件(事件能传递给它),如果不考虑拦截,那么后续的事件都会传递给它,考虑拦截,拦截后事件处理权交给viewgroup这个view(相当于viewgroup消费了ACTION_DOWN),如果没有view消费事件(ACTION_DOWN),activity消费之。