Android中Touch事件传递总结

TouchEvent

TouchEvent 分三种事件:down、move、up。

其中move事件在一个操作中(这里说的一个操作就是用户与屏幕的交互,即由down到up的动作序列)可能会发生多次。
但是,我们认为一个动作序列会包含以上三种事件,因此,在事件处理中就是要处理好这个过程,而最重要的就是down事件,这是一个动作序列的起始,没有down谈不上后面的事件了。
所以,我们把消耗down事件的类当做是这个动作序列的最终载体。

如果Down事件不归你处理,那这个动作序列的move,up也不归你处理。

他们的触发顺序会是这样:

ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE...->ACTION_MOVE->ACTION_UP

Touch事件传递的相关方法

android系统中的几乎所有View的子类都具有下面三个和TouchEvent处理密切相关的方法:

//这个方法用来分发TouchEvent
public boolean dispatchTouchEvent(MotionEvent ev)

//这个方法用来拦截TouchEvent 
//只有ViewGroup包含此方法,普通view不包含方法
 public boolean onInterceptTouchEvent(MotionEvent ev)

//这个方法用来处理TouchEvent 
public boolean onTouchEvent(MotionEvent ev)

onTouchEvent、onTouch

OnTouchListener接口是用来处理手机屏幕事件的监听接口,需要实现该接口的onTouch事件/OnClick事件来设置触发事件,然后我们可以通过setOnTouchListener()为任何需要的View的子类添加该监听器。

那么OnTouchListener接口中的onTouch方法 和 Touch事件的传递有什么关系呢?

在onTouchEvent的源码中有这样一段:

if (li != null && li.mOnClickListener != null) {  
            playSoundEffect(SoundEffectConstants.CLICK);  
           li.mOnClickListener.onClick(this);
            return true;  
        }

若我们又注册了onClick监听,则在onTouchEvent中就会执行该监听,同时返回true。

若没有注册onClick监听,顶层view的onTouchEvent默认返回false,其他层view的onTouchEvent默认返回true。

因此,如果onTouch返回了true,则事件被消费掉,就不再执行onTouchEvent了,更别说onClick监听了。如果onTouch返回false,那么会继续执行onTouchEvent,再执行onClick监听,若onTouchEvent中返回了true,则事件被消费掉,不再往下层view传递。

结论:onTouchListener的onTouch方法优先级比onTouchEvent高,会先触发。假若onTouchListener中的onTouch方法返回true,表示此次事件已经被消费了,那onTouchEvent是接收不到消息的。假如onTouch方法返回false,会接着触发onTouchEvent,反之onTouchEvent方法不会被调用。内置诸如click事件的实现等等都基于onTouchEvent,假如onTouch返回true,这些事件将不会被触发。

Touch事件传递简易的流程图:

Android中Touch事件传递总结

结合图来看过程:

如果返回值是 Super.dispatchTouchEvent ,意味着由onInterceptTouchEvent决定事件流向。

如果调用了Super.dispatchTouchEvent。 这样就会继续调用onInterceptTouchEvent事件。因此如果需要多个控件同时处理,则一定需要返回true,并调用Super.dispatchTouchEvent

也就是说想要把事件传递给子view,则Super.dispatchTouchEvent 是必不可少的。

任何view的onTouch或者onTouchEvent方法返回了true,则表示该事件就已经到此被消费掉了,不再往下传递。

其他:

  • Down事件在onInterceptTouchEvent()后返回true,则传递到onTouchEvent,当其返回true时,本次动作序列的后续事件不会再通过onInterceptTouchEvent了,而是在dispatchTouchEvent中直接传递于onTouchEvent。也就是说后续事件直接默认被该view的dispatchTouchEvent分发至onTouchEvent。
  • Down事件在onTouchEvent后返回false后导致本次事件没有被消费掉,则向上传递到父view的onTouchEvent,若返回true,则后续的move、up事件直接由父view的dispatchTouchEvent传递给自己的onTouchEvent,而不经过父view的onInterceptTouchEvent,后面的子view自然接收不到Touch事件。
  • onInterceptTouchEvent默认返回false,顶层view的onTouchEvent默认返回false,其他view的onTouchEvent默认返回true。
  • 如果我们在一个View中同时覆写了onClick、onLongClick及onTouchEvent的话,onTouchEvent是最先捕捉到ACTION_DOWN和ACTION_UP事件的,其次才可能触发onClick或者onLongClick。

GestureDetector手势识别类

通过重写View.OnTouchListener接口的onTouch(View v, MotionEvent event)方法,我们可以处理一些简单的touch事件,但是这个方法并不能识别手势,如果需要处理一些复杂的手势,用这个接口就会很麻烦(因为我们要自己根据用户触摸的轨迹去判断是什么手势)。好在Android为我们提供了GestureDetector类,通过它,我们可以轻松的进行手势识别。

为View和Activity加入手势操作的步骤如下:

1、为View或者Activity实现OnGestureListener接口,覆写需要的手势的回调方法。

2、创建一个GestureDetector对象mygesturedetector,设置其监听器。

3、覆写View或者Activity的OnTouchEvent方法,调用或返回mygesturedetector.onTouchEvent(ev),将事件交给mygesturedetector处理。

非常好的参考资料:

http://www.cnblogs.com/ghj1976/archive/2012/04/13/2445561.html  消息分发知识基础

http://ipjmc.iteye.com/blog/1694146     Android事件处理

http://www.longdw.com/touchevent-android/  Android的ViewGroup中事件的传递机制