(本文基于android-2.3.3_r1代码研究)
在Android Touch事件传递机制(一) – onInterceptTouchEvent & onTouchEvent这篇文章中研究了Android触屏事件的分发机制;本文继续深入研究。
OnTouchListener & onTouchEvent
首先我们来看看View的OnTouchListener与onTouchEvent方法的区别与联系,如下布局:
设置OnTouchListener:
运行demo,在MyView上按下触屏并滑动后松开,查看log:
E/Test5Activity﹕ onTouch:false action:ACTION_DOWN
E/MyView﹕ onTouchEvent:false action:ACTION_DOWN
可以看到,设置了OnTouchListener后,MyView收到down事件后首先回调OnTouchListener的onTouch方法,然后才会将down事件分发给MyView的onTouchEvent方法处理;由于onTouchEvent方法返回false,后续事件将不再分发给MyView。
onTouch方法默认返回false。那么我们返回true再运行一次试试:
E/Test5Activity﹕ onTouch:true action:ACTION_DOWN
E/Test5Activity﹕ onTouch:true action:ACTION_MOVE
E/Test5Activity﹕ onTouch:true action:ACTION_MOVE
......
E/Test5Activity﹕ onTouch:true action:ACTION_MOVE
E/Test5Activity﹕ onTouch:true action:ACTION_UP
可以看到,当onTouch方法返回true时,MyView的touch事件将不再分发给其onTouchEvent方法。我们看下OnTouchListener和onTouch的解释:
设置OnTouchListener回调之后,touch事件在分发给view之后,我们将有机会在目标view之前对这个touch事件进行响应;
onTouch方法返回true表示这个touch事件已被消费掉,这就意味着touch事件不会再继续分发给目标view。
OnTouchListener & OnClickListener
对MyView设置OnTouchListener 和 OnClickListener,onTouch方法返回false:
在按钮上按下触屏、移动、放开触屏,查看log:
E/Test5Activity﹕ onTouch:false action:ACTION_DOWN
E/MyView﹕ onTouchEvent:true action:ACTION_DOWN
E/Test5Activity﹕ onTouch:false action:ACTION_MOVE
E/MyView﹕ onTouchEvent:true action:ACTION_MOVE
E/Test5Activity﹕ onTouch:false action:ACTION_MOVE
E/MyView﹕ onTouchEvent:true action:ACTION_MOVE
......
E/Test5Activity﹕ onTouch:false action:ACTION_MOVE
E/MyView﹕ onTouchEvent:true action:ACTION_MOVE
E/Test5Activity﹕ onTouch:false action:ACTION_UP
E/MyView﹕ onTouchEvent:true action:ACTION_UP
E/Test5Activity﹕ onClick
可以看到,onTouch方法被调用了多次,分别对应了按下(ACTION_DOWN)、移动(ACTION_MOVE)、松开(ACTION_UP)等事件;onClick事件发生在ACTION_UP之后,只回调一次。
onTouch方法返回true再看下log:
可以看到,onClick方法不再被调用。这是因为在touch事件分发给onClick方法之前,被onTouch方法拦截并消费掉,因此不再分发给onClick方法。
#OnLongClickListener
再来看看OnLongClickListener与OnTouchListener 和 OnClickListener的调用时序关系。
先看下OnLongClickListener的注释:
OnLongClickListener接口定义了长按触屏的回调,当我们在一个view上点击并保持一段时间后,就会唤起这个回调。onLongClick返回true表示已经消费了这次长按,否则返回false。
给MyView设置OnLongClickListener,onLongClick方法默认返回false:
在MyView上按下触屏并滑动,一段时间后松开触屏:
E/Test5Activity﹕ onTouch:false action:ACTION_DOWN
E/Test5Activity﹕ onTouch:false action:ACTION_MOVE
E/Test5Activity﹕ onTouch:false action:ACTION_MOVE
......
E/Test5Activity﹕ onTouch:false action:ACTION_MOVE
E/Test5Activity﹕ onLongClick:false
E/Test5Activity﹕ onTouch:false action:ACTION_MOVE
......
E/Test5Activity﹕ onTouch:false action:ACTION_MOVE
E/Test5Activity﹕ onTouch:false action:ACTION_UP
E/Test5Activity﹕ onClick
可以看出,onClick在触屏抬起后触发;onLongClick方法在触屏抬起前触发,并需要手指按下超过一定时间;滑动手指不影响点击与长按事件的触发。
onLongClick方法返回true再看下:
E/Test5Activity﹕ onTouch:false action:ACTION_DOWN
E/Test5Activity﹕ onTouch:false action:ACTION_MOVE
E/Test5Activity﹕ onTouch:false action:ACTION_MOVE
......
E/Test5Activity﹕ onTouch:false action:ACTION_MOVE
E/Test5Activity﹕ onLongClick:true
E/Test5Activity﹕ onTouch:false action:ACTION_MOVE
E/Test5Activity﹕ onTouch:false action:ACTION_MOVE
......
E/Test5Activity﹕ onTouch:false action:ACTION_MOVE
E/Test5Activity﹕ onTouch:false action:ACTION_UP
可以看到,onLongClick方法返回true后,onClick方法就不再触发了,这是因为onLongClick消费了长按事件。
总结
-
设置OnTouchListener:onTouch方法返回false时,onTouch方法及View的onTouchEvent方法依次被调用;onTouch方法返回true时,只调用onTouch方法,onTouchEvent方法不再被调用
-
设置OnTouchListener后:onTouch方法返回false,不影响OnClickListener及OnLongClickListener的触发;onTouch方法返回true时,OnClickListener及OnLongClickListener不再触发
-
OnClickListener的触发条件是手指从触屏抬起;OnLongClickListener的触发条件是按下触屏且停留一段事件
-
onLongClick方法返回false不影响OnClickListener的触发;onLongClick方法返回true,OnClickListener不再触发
Demo代码
demo代码可以在我的github上下载:Android触屏事件传递演示Demo
相关文章
Android Touch事件传递机制(一) – onInterceptTouchEvent & onTouchEvent
Android Touch事件传递机制(三) – Touch事件分发(dispatchTouchEvent)
Android Touch事件传递机制(四) – Touch事件处理(onTouchEvent)