android事件的分发和消费机制(onTouchEvent())

来源:互联网 发布:电梯维修需要编程吗 编辑:程序博客网 时间:2024/06/10 03:29

一、简介  

              Activity或View类的onTouchEvent()回调函数会接收到touch事件。

              一个完整的手势是从ACTION_DOWN开始,到ACTION_UP结束。


        简单的情况下,我们只需要在onTouchEvent()中写个switch case语句,处理各种事件(Touch Down、 Touch Move、 Touch Up等),但是比较复杂的动作就需要更多的处理了。

       ViewGroup作为一个parent是可以截获传向它的child的touch事件的。

       如果一个ViewGrouponInterceptTouchEvent()方法返回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)

能够响应这些方法的控件包括:ViewGroupViewActivity。方法与控件的对应关系如下表所示:

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的某些子类(GridViewScrollView...)重写了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的事件拦截逻辑如下:

  1. 如果 onInterceptTouchEvent 返回 true,则表示将事件进行拦截,并将拦截到的事件交由当前 View 的 onTouchEvent 进行处理; 
  2. 如果 onInterceptTouchEvent 返回 false,则表示将事件放行,当前 View 上的事件会被传递到子 View 上,再由子 View 的 dispatchTouchEvent
  3. 来开始这个事件的分发; 
  4. 如果 onInterceptTouchEvent 返回 super.onInterceptTouchEvent(ev),事件默认不会被拦截,

(三)、事件响应:

public boolean onTouchEvent(MotionEvent ev)

在 dispatchTouchEvent返回 super.dispatchTouchEvent(ev) 并且onInterceptTouchEvent 返回 true的情况下 onTouchEvent 会被调用。onTouchEvent 的

事件响应逻辑如下:

  1. 如果事件传递到当前 View 的 onTouchEvent 方法,而该方法返回了 false,那么这个事件会从当前 View 向上传递,并且都是由上层 View 的 onTouchEvent
  2. 来接收,如果传递到上面的 onTouchEvent 也返回 false,这个事件就会“消失”,而且接收不到下一次事件。 
  3. 如果返回了 true 则会接收并消费该事件。 
  4. 如果返回 super.onTouchEvent(ev) 默认处理事件的逻辑和返回 false 时相同。

(四)、使用要点:

onInterceptTouchEvent用于改变事件的传递方向。决定传递方向的是返回值,返回为false时事件会传递给子控件,返回值为true时事件会传递给当前控件的onTouchEvent(),这就是所谓的Intercept(拦截)。

正确的使用方法是,在此方法内仅判断事件是否需要拦截,然后返回。如果需要拦截直接返回true,然后由onTouchEvent方法进行处理。


onTouchEvent用于处理事件,返回值决定当前控件是否消费(consume)了这个事件。尤其对于ACTION_DOWN事件,返回true,表示我想要处理后续事件;

返回false,表示不关心此事件,并返回由父类进行处理。


可能你要问是否消费了有区别吗,反正我已经针对事件编写了处理代码?答案是有区别!比如ACTION_MOVE或者ACTION_UP发生的前提是一定曾经发生了ACTION_DOWN,如果你没有消费ACTION_DOWN,那么系统会认为ACTION_DOWN没有发生过,所以ACTION_MOVE或者ACTION_UP就不能被捕获。

在没有重写onInterceptTouchEvent()和onTouchEvent()的情况下(他们的返回值都是false)

(五)、示例图:


0 0
原创粉丝点击