Activity或View类的onTouchEvent()回调函数会接收到touch事件。
一个完整的手势是从ACTION_DOWN开始,到ACTION_UP结束。
简单的情况下,我们只需要在onTouchEvent()中写个switch case语句,处理各种事件(Touch Down、 Touch Move、 Touch Up等),但是比较复杂的动作就需要更多的处理了。
ViewGroup作为一个parent是可以截获传向它的child的touch事件的。
如果一个ViewGroup的onInterceptTouchEvent()方法返回true,说明Touch事件被截获,子View不再接收到Touch事件,而是转向本ViewGroup的 onTouchEvent()方法处理。从Down开始,之后的Move,Up都会在相应的onTouchEvent()方法中处理。
如果onInterceptTouchEvent()返回false,则事件会交给child view处理。
Android中提供了ViewGroup、View、Activity三个层次的Touch事件处理。
处理过程是按照Touch事件从上到下传递,再按照是否消费的返回值,从下到上返回,即如果View的onTouchEvent返回false,将会向上
传给它的parent的ViewGroup,如果ViewGroup不处理,将会一直向上返回到Activity。即隧道式向下分发,然后冒泡式向上处理。
Android 中与 Touch 事件相关的方法包括:dispatchTouchEvent(MotionEventev)、onInterceptTouchEvent(MotionEvent ev)、onTouchEvent(MotionEvent ev);
能够响应这些方法的控件包括:ViewGroup、View、Activity。方法与控件的对应关系如下表所示:
Touch 事件相关方法 |
方法功能 |
ViewGroup |
View |
Activity |
public boolean dispatchTouchEvent(MotionEvent ev) |
事件分发 |
Yes |
Yes |
Yes |
public boolean onInterceptTouchEvent(MotionEvent ev) |
事件拦截 |
Yes |
No |
No |
public boolean onTouchEvent(MotionEvent ev) |
事件响应 |
Yes |
Yes |
Yes |
从这张表中我们可以看到 ViewGroup 对与 Touch 事件相关的三个方法均能响应,而 Activity 和 View对 onInterceptTouchEvent(MotionEvent ev) 也就是
事件拦截不进行响应。
dispatchTouchEvent() |
用来分派事件。 其中调用了onInterceptTouchEvent()和onTouchEvent(),一般不重写该方法 |
onInterceptTouchEvent() |
用来拦截事件。 ViewGroup类中的源码实现就是{return false;}表示不拦截该事件, 事件将向下传递(传递给其子View); 若手动重写该方法,使其返回true则表示拦截,事件将终止向下传递, 事件由当前ViewGroup类来处理,就是调用该类的onTouchEvent()方法 |
onTouchEvent() |
用来处理事件。 返回true则表示该View能处理该事件,事件将终止向上传递(传递给其父View); 返回false表示不能处理,则把事件传递给其父View的onTouchEvent()方法来处理 |
【注】:ViewGroup的某些子类(GridView、ScrollView...)重写了onInterceptTouchEvent()方法,当发生ACTION_MOVE事件时,返回true进行拦截。
Touch 事件分析
public boolean dispatchTouchEvent(MotionEvent ev)
Touch 事件发生时 Activity 的dispatchTouchEvent(MotionEvent ev) 方法会以隧道方式(从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递)将事件传递给最外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法,并由该View 的 dispatchTouchEvent(MotionEvent ev) 方法对事件进行分发。
</pre><pre name="code" class="java"><span style="font-size:18px;">public boolean onInterceptTouchEvent(MotionEvent ev)</span>
在外层 View 的dispatchTouchEvent(MotionEvent ev) 方法返回系统默认的super.dispatchTouchEvent(ev) 情况下,事件会自动的分发给当前 View 的
onInterceptTouchEvent 方法。onInterceptTouchEvent的事件拦截逻辑如下:
public boolean onTouchEvent(MotionEvent ev)
在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且onInterceptTouchEvent 返回 true的情况下 onTouchEvent 会被调用。onTouchEvent 的
事件响应逻辑如下:
l onInterceptTouchEvent用于改变事件的传递方向。决定传递方向的是返回值,返回为false时事件会传递给子控件,返回值为true时事件会传递给当前控件的onTouchEvent(),这就是所谓的Intercept(拦截)。
l 正确的使用方法是,在此方法内仅判断事件是否需要拦截,然后返回。如果需要拦截直接返回true,然后由onTouchEvent方法进行处理。
l onTouchEvent用于处理事件,返回值决定当前控件是否消费(consume)了这个事件。尤其对于ACTION_DOWN事件,返回true,表示我想要处理后续事件;
返回false,表示不关心此事件,并返回由父类进行处理。
l 可能你要问是否消费了有区别吗,反正我已经针对事件编写了处理代码?答案是有区别!比如ACTION_MOVE或者ACTION_UP发生的前提是一定曾经发生了ACTION_DOWN,如果你没有消费ACTION_DOWN,那么系统会认为ACTION_DOWN没有发生过,所以ACTION_MOVE或者ACTION_UP就不能被捕获。
l 在没有重写onInterceptTouchEvent()和onTouchEvent()的情况下(他们的返回值都是false)