文档章节

Android事件传递机制

k
 kim366
发布于 2016/05/13 19:13
字数 2168
阅读 5
收藏 0

      总结自其它人的博客,感觉比较清晰。


     参考:www.trinea.cn


Android Touch事件传递机制

介绍Android Touch事件的传递机制

不少朋友私信问到这个问题,那就推荐一篇我看到的对传递机制介绍最清楚的国外文章吧。本文略作翻译。

 

1、基础知识

(1) 所有Touch事件都被封装成了MotionEvent对象,包括Touch的位置、时间、历史记录以及第几个手指(多指触摸)等。

 

(2) 事件类型分为ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每个事件都是以ACTION_DOWN开始ACTION_UP结束。

 

(3) 对事件的处理包括三类,分别为传递——dispatchTouchEvent()函数、拦截——onInterceptTouchEvent()函数、消费——onTouchEvent()函数和OnTouchListener

 

2、传递流程

(1) 事件从Activity.dispatchTouchEvent()开始传递,只要没有被停止或拦截,从最上层的View(ViewGroup)开始一直往下(子View)传递。子View可以通过onTouchEvent()对事件进行处理。

 

(2) 事件由父View(ViewGroup)传递给子View,ViewGroup可以通过onInterceptTouchEvent()对事件做拦截,停止其往下传递。

 

(3) 如果事件从上往下传递过程中一直没有被停止,且最底层子View没有消费事件,事件会反向往上传递,这时父View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到Activity的onTouchEvent()函数。

 

(4) 如果View没有对ACTION_DOWN进行消费,之后的其他事件不会传递过来。

 

(5) OnTouchListener优先于onTouchEvent()对事件进行消费。

 

上面的消费即表示相应函数返回值为true。

 

更多请直接阅读PDF英文原文:Mastering the Android Touch System


自己对源码的分析:触摸屏事件的传递机制源码分析

          ViewGroup中onInterceptTouchEvent();
Implement this method to intercept all touch screen motion events. This allows you to watch events as they are dispatched to your children, and take ownership of the current gesture at any point.

Using this function takes some care, as it has a fairly complicated interaction with View.onTouchEvent(MotionEvent), and using it requires implementing that method as well as this one in the correct way. Events will be received in the following order:

     实现这个方法可以打断所有的触摸屏事件,并且在触摸屏事件被分发到子视图时,允许你监管这些事件,随时获取事件的所有权。
使用这个方法,需要考虑到很多方面, 因为这个方法和onTouchEvent()方法的交互比较复杂,使用这个方法 要求同样准确地实现onTouchEvent()方法。事件会以下面的顺序传递和接收:
1.  You will receive the down event here. 
     本方法收到按下事件 DOWN
2.  The down event will be handled either by a child of this view group, or given to your own onTouchEvent() method to handle; this means you should implement onTouchEvent() to return true, so you will continue to see the rest of the gesture (instead of looking for a parent view to handle it). Also, by returning true from onTouchEvent(), you will not receive any following events in onInterceptTouchEvent() and all touch processing must happen in onTouchEvent() like normal
       按下事件被当前视图的子视图处理,或被传递到当前viewgroup的onTouchEvent()方法中处理; 这就意味着,你需要实现onTouchEvent方法并返回true, 然后接着看剩下的其他手势(而不是寻找一个父视图处理), 其次, 通过在onTouchEvent中返回true后,你将不会再通过onInterceptTouchEvent()收到接下来其余的事件,并且所有的触屏事件处理都必须像通常情况一样在onTouchEvent中处理。
3.  For as long as you return false from this function, each following event (up to and including the final up) will be delivered first here and then to the target's onTouchEvent().
       只要你在本方法中返回false,那么接下来的所有事件都会再次被传递进来,然后寻找目标视图的onTouchEvent()方法。
4.  If you return true from here, you will not receive any following events: the target view will receive the same event but with the action  MotionEvent.ACTION_CANCEL , and all further events will be delivered to your onTouchEvent() method and no longer appear here.
     如果你通过本方法返回true, 那么你将收不到接下来的所有事件,目标视图将受到相同的事件,不过, 同时伴随着事件MotionEvent.ACTION_CANCEL,并且所有接下来的事件都将被传递到当前视图的onTouchEvent()中,再也不会出现在本方法中。
参数:
ev - The motion event being dispatched down the hierarchy.
返回:
Return true to steal motion events from the children and have them dispatched to this ViewGroup through onTouchEvent(). The current target will receive an ACTION_CANCEL event, and no further messages will be delivered here.
           public boolean onInterceptTouchEvent(MotionEvent ev) {
                return false;
          }


View中onTouchEvent()
/**
     * Implement this method to handle touch screen motion events.
     * <p>
     * If this method is used to detect click actions, it is recommended that
     * the actions be performed by implementing and calling
     * { @link #performClick()}. This will ensure consistent system behavior,
     * including:
     * <ul>
     * <li>obeying click sound preferences
     * <li>dispatching OnClickListener calls
     * <li>handling { @link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when
     * accessibility features are enabled
     * </ul>
     *
     * @param event The motion event.
     * @return True if the event was handled, false otherwise.
     */
 public boolean onTouchEvent(MotionEvent event);

 Android的Touch事件处理机制比较复杂,特别是在考虑了多点触摸以及事件拦截之后。

      Android的Touch事件处理分3个层面:Activity层,ViewGroup层,View层。

      首先说一下Touch事件处理的几条基本规则。

      1.如果在某个层级没有处理ACTION_DOWN事件,那么该层就再也收不到后续的Touch事件了直到下一次ACTION_DOWN事件。

         说明:a.某个层级没有处理某个事件指的是它以及它的子View都没有处理该事件。

                 b.这条规则不适用于Activity层(它是顶层),它们可以收到每一个Touch事件。

                 c.如果没有处理ACTION_MOVE这类事件,不会有任何影响。

      2.如果ACTION_DOWN事件发生在某个View的范围之内,则后续的ACTION_MOVE,ACTION_UP和ACTION_CANCEL等事件都将被发往该View,即使事件已经出界了。

      3.第一根按下的手指触发ACTION_DOWN事件,之后按下的手指触发ACTION_POINTER_DOWN事件,中间起来的手指触发ACTION_POINTER_UP事件,最后起来的手指触发ACTION_UP事件(即使它不是触发ACTION_DOWN事件的那根手指)。

      4.pointer id可以用于跟踪手指,从按下的那个时刻起pointer id生效,直至起来的那一刻失效,这之间维持不变。

      5.如果一个ACTION_DOWN事件被父View拦截了,则任何子View不会再收到任何Touch事件了(这符合第1点的要求)。

      6.如果一个非ACTION_DOWN事件被父View拦截了,则那些上次处理了ACTION_DOWN事件的子View会收到一个ACTION_CANCEL事件,之后不会再收到任何Touch事件了,即使父View不再拦截后续的Touch事件。

      7.如果父View决定处理Touch事件或者子View没有处理Touch事件,则父View按照普通View的处理方式处理Touch事件,否则它根本不处理Touch事件(它只负责分发)。

      8.如果父View在onInterceptTouchEvent中拦截了事件,则onInterceptTouchEvent中不会再收到Touch事件了,事件被直接交给它自己处理(按照普通View的处理方式)。

      下面分层讲述一些细节。

      1.Activity层:


publicboolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) { //在这里交给View层处理returntrue;
        }
        return onTouchEvent(ev); // 如果View层没有处理,则在这里处理
}

      2.View层:


publicboolean dispatchTouchEvent(MotionEvent event) {
         // 省略了部分细节
         ListenerInfo li = mListenerInfo;
         if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
             returntrue;
         }
         if (onTouchEvent(event)) {
             returntrue;
         }
        returnfalse;
}

      View的onTouch方法代码比较多,主要的逻辑分两步:先是将事件交给TouchDelegate处理(如果有的话),如果TouchDelegate没有处理再自行处理;自行处理主要负责View状态的变换(如按下状态),长按事件,点击事件的检测与触发等。

      3.ViewGroup层(比较复杂):

      ViewGroup层处理Touch事件的总体逻辑是:先检测是否需要拦截,没有拦截的话下发给子View处理,如果子View没有处理再自行处理,自行处理的逻辑与View一样。

      拦截的逻辑是,将从down到up之间的所有事件看作一组事件,如果从down就拦截了,则组内的后续其它事件完全交给自己处理,不需要再进入拦截逻辑了;如果是从中间拦截,则先给子View发送cancel事件,组内的后续其它事件完全交给自己处理,不需要再进入拦截逻辑了。

      分发的逻辑是,在ACTION_DOWN事件的时候,寻找子View进行处理,称为寻找Target;如果没有找到Target,则自行处理;如果找到Target,则交由Target处理。

      从代码上看,dispatchTouchEvent负责分发逻辑,onTouchEvent负责真正的处理逻辑,一般应该重载onTouchEvent,只有特殊情况下才需要重载dispatchTouchEvent。




本文转载自:http://blog.csdn.net/oyangyujun/article/details/47974435

共有 人打赏支持
k
粉丝 1
博文 129
码字总数 0
作品 0
朝阳
Android 机制篇 - 事件分发机制超详解(🔥🔥🔥🔥🔥🔥🔥🔥)

Android 虽然不是四大组件,但其并不比四大组件的地位低(涉及面的广度和深入甚至比四大组件还复杂🔥)。而View的核心知识点“事件分发机制”则是不少刚入门同学的拦路虎(1、项目中处处遇...

Pepsimaxin
07/12
0
0
安卓自定义View进阶-事件分发机制原理

安卓自定义View进阶-事件分发机制原理 之前讲解了很多与View绘图相关的知识,你可以在 安卓自定义View教程目录 中查看到这些文章,如果你理解了这些文章,那么至少2D绘图部分不是难题了,大部...

猴亮屏
05/22
0
0
【Android翻译】组件通信模式

目标:避免紧耦合 本文对原文进行了精简 原文链接:Communication patterns for application components 紧耦合 组件之间相互持有引用,以及直接调用方法.在下面的代码中,MenuFragment持有Magaz...

xesam
2015/04/23
0
0
onInterceptTouchEvent和onTouchEvent调用时序

onInterceptTouchEvent()是ViewGroup的一个方法,目的是在系统向该ViewGroup及其各个childView触发onTouchEvent()之前对相关事件进行一次拦截,Android这么设计的想法也很好理解,由于ViewG...

yzp531
2013/04/25
0
0
Android中父View和子view的点击事件的执行过程

Android中的事件类型分为按键事件和屏幕触摸事件,Touch事件是屏幕触摸事件的基础事件,有必要对它进行深入的了解。 一个最简单的屏幕触摸动作触发了一系列Touch事件:ACTIONDOWN->ACTIONMOV...

火云
2015/06/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

设计模式之 明确责任 观察者模式 状态模式 责任链模式

观察者模式是任务分发的一种模式。 如果认为我们设计的系统的各个模块(或子系统)的最终目的是完成共同任务,那么这个任务如何分配到多个模块的就是我们遇到的第一个问题。简单设计场合我们...

backbye
15分钟前
2
0
14-利用思维导图梳理JavaSE-大汇总

14-利用思维导图梳理JavaSE-Java基础知识大汇总 主要内容 1.对象入门 2.一切都是对象 3.程序流程控制 4.初始化和消除 5.权限访问控制 6.复用类 7.多态 8.接口与抽象类 9.内部类 10.容器 11.异...

飞鱼说编程
51分钟前
5
0
利用Lombok编写优雅的spring依赖注入代码,去掉繁人的@Autowired

大家平时使用spring依赖注入,都是怎么写的? @Servicepublic class OrderService { @Autowired private UserService userService;} 是不是很熟悉的感觉?但是呢 如果你用...

HeyS1
58分钟前
25
0
IBATIS 写BLOB字段遇到的问题

1、 首先遇到的配置问题,通过设置typeHandler 来支持写入。接下来由此引出了事务的问题。 <typeHandler jdbcType="BLOB" javaType="[B" callback="org.springframework.orm.ibatis.support....

echo-neo
今天
1
0
37. Sudoku Solver

Description tags: backtrack,hash table difficulty: hard Write a program to solve a Sudoku puzzle by filling the empty cells.A sudoku solution must satisfy all of the following......

52iSilence7
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部