Android点击事件分发机制
dispatchTouchEvent:决定了事件是否继续分发下去和是否响应事件,false:继续分发,true:不继续分发,此次事件到此结束,也不会有任何控件执行onTouchEvent方法。
onInterceptTouchEvent:决定了是否拦截该事件,false:不拦截,true:拦截,此时当前控件执行onTouchEvent方法。
onTouchEvent:决定了是否消费该事件,false:不消费,true:消费。
四种常见情况
不拦截,不消耗:
不拦截会重新交由上层处理,不消耗down事件之后的事件不会往下分发
拦截不消耗
消耗不拦截
拦截并消耗
.
OnTouchListener、OnTouchEvent、OnClickListener事件分发顺序
1、调用顺序,OnTouchListener.onTouch()——>onTouchEvent()——>OnClickListener.onClick(),其中若onTouch返回值为true,则会屏蔽掉onTouchEvent方法和OnClickListener.onClick方法,若onTouchEvent方法可以被调用,则OnClickListener.onClick方法也一定可以被调用。
2、一系列点击事件,肯定是以down事件开始,以up事件结束,中间若干个move事件。如果一旦某个元素拦截了某个事件,那么同一个事件序列内的所有事件都会直接交给它处理。(详见Android开发艺术探索P142)
3、首先,考虑OnTouchListener.onTouch返回的是false,此种情况下,首先down事件按照顺序先经过OnTouchListener.onTouch方法,由于返回false不屏蔽onTouchEvent方法,所以又被分发到onTouchEvent方法,由于该方法默认返回true(详见Android开发艺术探索P143),即消费了down事件,所以此后的所有事件都由该方法处理,并且不再经过OnTouchListener.onTouch。可以看下图log证实了这点,当手指试图滑动时,down事件分别经过两个方法,其他的事件只经过onTouchEvent
滑动冲突:分为三种
1.外部滑动方向和内部滑动方向不一致
典型一个左右滑动的Viewpager+上下滑动的Fragment(Viewpager已经处理了滑动冲突)
2.外部滑动方向和内部滑动方向一致
3.上述两种情况的嵌套
对于情况一,判断用户是上下滑动还是左右滑动,可以根据角度,距离差,速度差来进行判断
对于情况二,要根据业务情况来处理规则
外部拦截法:父容器覆写onIntercepted方法,根据情况是否拦截消耗事件(通常选用该方法)
内部拦截法:父容器不做处理,由子控件是否拦截和消耗(要配合requestDisallowInterceptTouchEvent()来使用,父容器不能拦截ACTION_DOWN,因为该事件不受requestDisallowInterceptTouchEvent()控制)