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消费之。