Android视图架构及事件分发处理机制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/reakingf/article/details/52029575

转载请标明出处:
http://blog.csdn.net/reakingf/article/details/52029575
本文出自:方耿佳的博客

1、视图View结构

在Android系统中,视图的结构是一种树形结构,父级View一般是个ViewGroup,而子View可以使ViewgGroup也可以是简单的View,这种树形结构称为View树或控件树。每一颗控件树的顶部都有一个ViewParent对象,且都以深度优先遍历来查找子View元素,下面给个例子表示下View树。

这里写图片描述

2、UI界面结构

我们都知道在Android中与用户进行互动的UI界面通常对应一个Activity,但是这个UI界面的结构是怎样的呢?让我们一起来看看。
每个Activity都会有一个Window对象,一般是PhoneWindow,而PhoneWindow下就是视图结构啦,最顶层的View称为root view,一般是一个DecorView,其中包含两个子结构:TitleView和ContentView。我们平时在onCreate()中调用的setContentView()就是设置activity的contentView,具体结构图如下。

这里写图片描述

当我们在onCreate()中调用setContentView()方法后,ActivityManagerService会回调onResume()方法,此时系统才会把整个DecorView添加到PhoneWindow中,并显示出来。

3、事件分发机制

Android中的事件分发机制主要由Touch事件触发,处理对象是ViewGroup和View。任何Touch事件都是以MotionEvent.ACTION_DOWN开始,以ACTION_UP或CANCEL结束,中间可能会有一个或多个ACTION_MOVE。其中,在Android的事件处理机制中,主要涉及3个方法:

  • dispatchTouchEvent:负责事件分发的方法,该方法会调用onTouch()onTouchEvent()(见下文)两个方法,但是onTouch()优先于onTouchEvent(),所以如果onTouch()返回ture则相当于该事件被onTouch 消费了,不再执行onTouchEvent(),其中onClick() 方法的执行就是在onTouchEvent() 调用的。不过onTouch() 要执行,必须满足两个条件,即mOnTouchListener的值不能为空(一般我们在setOnTouchListener() 中对其进行赋值),和当前点击的控件必须是enable 的。

  • onInterceptTouchEvent:负责事件拦截的方法,只存在于ViewGroup中,普通View中没有该方法。用于拦截向下分发的事件,若返回值为true则拦截,false则不拦截,继续向下分发。

  • onTouchEvent:负责事件处理的方法,若返回值为false,则处理完事件后会将事件继续向上级传递,上级视图对该事件继续进行处理,即执行上级视图的onTouchEvent方法,若所有视图都不处理该事件,则最终该事件将传递给Activity处理;若为返回值true,则不再向上级视图传递;

具体逻辑是:当一个Touch Event发生时,都是从当前Acitivity开始,即Activity –> Window –> View ,顶级View接收到事件后,按照事件分发机制向下逐级分发事件。所以也可以直接当成由ViewGroup处理,即由最顶级的DecorView开始处理,DecorView获得事件后便开始向下级进行事件分发,然后获得事件的子级ViewGroup判断是否要拦截此事件,若要拦截,则该事件序列由该级视图处理,不再向下传递;若不拦截则继续往下分发,直到到达最底层,此时的最底层View执行onTouchEvent并判断是否向上级反映处理情况,若返回值为false,则可以理解为当前View没能处理好该事件,所以将继续向上级传递,由上级View继续调用onTouchEvent进行处理,该事件的后续事件(如ACTION_MOVE)也是这样传递的。即上面3个方法的执行顺序是: dispatchTouchEvent–> onInterceptTouchEvent–> onTouchEvent

这里写图片描述

Tips:

  1. 若ViewGroup拦截最初的ACTION_DOWN,则该事件将传给该ViewGroup的onTouchEvent方法处理;
  2. 若ViewGroup拦截了一个中间事件,如ACTION_MOVE,则该事件将被系统处理为CANCEL事件,并传递给其子View,但不传递给自己的onTouchEvent,但在该事件后面的事件将只传递给该ViewGroup的onTouchEvent方法处理。即某个View决定拦截某个事件后,就默认它要拦截该事件序列,所以该事件序列内的所有事件都直接交给它处理,且不需再调用onInterceptEvent方法

猜你喜欢

转载自blog.csdn.net/reakingf/article/details/52029575