Andoid Touch事件分发机制 及与OnClick的调用机制

来源:互联网 发布:苏州相城区淘宝培训 编辑:程序博客网 时间:2024/05/29 19:52

声明:本文是参考网上多篇文章来写,通过自己的测试发现有些不太细致的地方,故写这篇整体的分发机制的总结。

下面是参考的文章来源: sunzn'Blog    Android 编程下 Touch 事件的分发和消费机制

                                              张兴业的博客          Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()

                                              林J                            Android:30分钟弄明白Touch事件分发机制


下面进入正题

首先是动作常量,最常用的三个动作。一般是DOWN Move Move Move...Up   

常见的动作常量:

ACTION_DOWN                          单点触摸动作

ACTION_UP                                 单点触摸离开动作

ACTION_MOVE                           触摸点移动动作

事件传递的主角是ACTION_DOWN事件,Down事件找到目标时,MOVE和UP事件才会传递给目标。

然后是事件传递 的三个方法 dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent


这里的view是指没有子view的view(如button),View和Activity不存在onInterceptTouchEvent,Activity作为最顶层,要向下分发,无需拦截,而view最为最底层,也不用拦截事件,事件拦截方法主要发生在中间传递的viewGroup.

下面介绍下事件分发的整体流程

先说下方法返回值

▐ 事件分发:public boolean dispatchTouchEvent(MotionEvent ev)

Touch 事件发生时 Activity 的 dispatchTouchEvent(MotionEvent ev) 方法会以隧道方式(从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递)将事件传递给最外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法,并由该 View 的 dispatchTouchEvent(MotionEvent ev) 方法对事件进行分发。dispatchTouchEvent 的事件分发逻辑如下:

  • 如果 return true,事件会分发给当前 View 并由 dispatchTouchEvent 方法进行消费,同时事件会停止向下传递;
  • 如果 return false,事件分发分为两种情况:
  1. 如果当前 View 获取的事件直接来自 Activity,则会将事件返回给 Activity 的 onTouchEvent 进行消费;
  2. 如果当前 View 获取的事件来自外层父控件,则会将事件返回给父 View 的  onTouchEvent 进行消费。
  3. 总体来说就是返回给当前view的上一层的OnTouchEvent方法来处理
  • 如果返回系统默认的 super.dispatchTouchEvent(ev),事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。

▐ 事件拦截:public boolean onInterceptTouchEvent(MotionEvent ev) 

外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系统默认的 super.dispatchTouchEvent(ev) 情况下,事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。onInterceptTouchEvent 的事件拦截逻辑如下:

  • 如果 onInterceptTouchEvent 返回 true,则表示将事件进行拦截,并将拦截到的事件交由当前 View 的 onTouchEvent 进行处理;
  • 如果 onInterceptTouchEvent 返回 false,则表示将事件放行,当前 View 上的事件会被传递到子 View 上,再由子 View 的 dispatchTouchEvent 来开始这个事件的分发;
  • 如果 onInterceptTouchEvent 返回 super.onInterceptTouchEvent(ev),这里要分为两种情况,如果当前控件有子View,那么此时相当于返回false;如果没有子view那就相当于true。

▐ 事件响应:public boolean onTouchEvent(MotionEvent ev)

在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true 或返回 super.onInterceptTouchEvent(ev) 的情况下 onTouchEvent 会被调用。onTouchEvent 的事件响应逻辑如下:

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

总结一下,基本方法返回true就是能处理事件,false是不能处理事件。

现在看上面流程,首先当我们触摸时ACTION_DOWN触发Activity,然后Activity将动作事件发给最外层的ViewGroup,如下图所示,然后在遍历传给往里层的view


消息下发顺序是这样的:①-②-⑤-⑥-⑦-③-④

在上述例子中如果⑤的dispatchTouchEvent返回结果为true,那么⑥-⑦-③-④将都接收不到本次Touch事件。

Activityd的dispatchTouchEvent方法将事件分发给ViewGroup的dispatchTouchEvent,默认返回值情况下会传递给ViewGroup的onInterceptTouchEvent ,onInterceptTouchEvent 决定是否拦截事件,拦截的话交给自己的onTouchEvent来处理,不拦截就交给下一层VIew的ispatchTouchEvent方法处理,以此循环下去。

需要注意的是,如果ViewGroup在你点击区域没有子View,onInterceptTouchEvent方法的默认会传给自身的onTouchEvent方法。

view如果在自身onTouchEvent方法返回false,即未处理,动作事件回传给上一层的onTouchEvent方法来处理,只要没有处理,会一直向上层传递。

刚开始传递的是Action_Down事件,直到找到要处理事件的控件,Action_up Action_move才会从Activity传递过来。

另外就是OnTouchEvent方法,与onClick监听重叠的问题,在测试中,我用button做最底层VIew发现即使返回系统默认值,onTouchEvent依旧消费了动作事件,就以为最底层单一View会直接消费事件,而将button设为不能点击,情况又变正常了,所以这里是监听的问题,Down+Up形成一次Click.接下来我自己设置监听,并打印信息,onTouchEvent在返回默认值情况下,信息打印出来了,说明出发了监听。然后将onTouchEvent返回值设为True,事件被onTouchEvent消费,而且没有打印信息,说明事件被onTouchEvent消费后,监听就失效了。

0 0