本文讲的是Android视图的绘制的三大流程,视图的工做流程主要是指测量,布局,绘制这三大流程,即测量,布局和绘制,其中测量肯定查看的测量宽高,布局根据测量的宽高肯定视图在其父视图中的四个顶点的位置,而平局则将查看绘制到屏幕上,这样经过一个ViewGroup的递归遍历,一个景观树就展示在屏幕上了。说的简单,下面带你们一步一步从源码中分析:java
安卓的视图是树形结构的:微信
基本概念布局
在介绍视图的三大流程以前,咱们必须先介绍一些基本的概念,才能更好地理解这整个过程。this
窗口的概念orm
窗口表示的是一个窗口的概念,它是站在WindowManagerService角度上的一个抽象的概念,安卓中全部的视图都是经过窗口来呈现的,不论是活动,对话仍是面包,只要有浏览的地方就必定有窗口。对象
这里须要注意的是,这个抽象的窗口概念和PhoneWindow这个类并非同一个东西,PhoneWindow表示的是手机屏幕的抽象,它充当活动和DecorView之间的媒介,就算没有PhoneWindow也是能够展现查看的。blog
抛开一切,仅站在WindowManagerService的角度上,安卓的界面就是由一个个窗口层叠展示的,而窗户又是一个抽象的概念,它并非实际存在的,它是以景观的形式存在,这个视图就是DecorView。继承
关于窗口这方面的内容,咱们这里先了解一个大概递归
DecorView的概念事件
DecorView是整个窗口界面的最顶层视图,视图的测量,布局,绘制,事件分发都是由DecorView往下遍历这个景观树.DecorView做为顶级景观,通常状况下它内部会包含一个竖直方向的LinearLayout中,在这个的LinearLayout里面有上下两个部分(具体状况和的Android的版本及主题有关),上面是【标题栏】,下面是【内容栏】。在活动中咱们经过的setContentView所设置的布局文件其实就是被加载到【内容栏】中的,而内容栏的ID是内容,所以指定布局的方法叫setContent()。
的ViewRoot的概念
的ViewRoot对应于ViewRootImpl类,它是链接的WindowManager和DecorView的纽带,查看的三大流程均是经过的ViewRoot来完成的。在ActivityThread中,当活动对象被建立完以后,会讲DecorView添加到窗口中,同时会建立对应的ViewRootImpl,并将ViewRootImpl和DecorView创建关联,并保存到WindowManagerGlobal对象中。
Java的
查看的绘制流程是从的ViewRoot的performTraversals方法开始的,它通过测量,布局和绘制三个过程才能最终将一个视图绘制出来,大体流程以下图:
测量测量
为了更好地理解查看的测量过程,咱们还须要理解MeasureSpec,它是搜索的一个内部类,它表示对查看的测量规格.MeasureSpec表明一个32位INT值,高2位表明SpecMode(测量模式),低30位表明SpecSize(测量大小),咱们能够看看它的具体实现:
Java的
MeasureSpec经过将SpecMode和SpecSize打包成一个INT值来避免过多的对象内存分配,并提供了打包和解包的方法。
SpecMode有三种类型,每一类都表示特殊的含义:
UNSPECIFIED
父容器不对视图有任何限制,要多大就给多大,这种状况通常用于系统内部,表示一种测量的状态;
究竟
父容器已经检测出查看所需的精确大小,这个时候搜索的最终打消就是SpecSize所指定的值。它对应于的LayoutParams中的match_parent和具体数值这两种模式。
最多
父容器指定了一个可用大小即SpecSize,查看的大小不能大于这个值,具体是什么值要看不一样观的具体实现。它对应于的LayoutParams中WRAP_CONTENT。
查看的MeasureSpec是由父容器的MeasureSpec和本身的的LayoutParams决定的,可是对于DecorView来讲有点不一样,由于它没有父类。在ViewRootImpl中的measureHierarchy方法中有以下一段代码展现了DecorView的MeasureSpec的建立过程,其中desiredWindowWidth和desireWindowHeight是屏幕的尺寸大小:
ViewGroup中的措施
Java的
再看看getRootMeasureSpec方法:
Java的
经过以上代码,DecorView的MeasureSpec的产生过程就很明确了,由于DecorView是FrameLyaout的子类,属于ViewGroup中,对于ViewGroup中来讲,除了完成本身的测量过程外,还会遍历去调用全部子元素的测量方法,各个子元素再递归去执行这个过程。和查看不一样的是,一个ViewGroup是一个抽象类,他没有重写查看的onMeasure方法,这里很好理解,由于每一个具体的ViewGroup中实现类的功能是不一样的,如何测量应该让它本身决定,好比LinearLayout中和RelativeLayout的。
所以在具体的一个ViewGroup中须要遍历去测量子查看,这里咱们看看一个ViewGroup中提供的测量子视图的measureChildWithMargins方法:
Java的
上述方法会对子元素进行测量,在调用子元素的测量方法以前会先经过getChildMeasureSpec方法来获得子元素的MeasureSpec。从代码上看,子元素的MeasureSpec的建立与父容器的MeasureSpec和自己的的LayoutParams有关,此外和查看的保证金和父类的填充有关,如今看看getChildMeasureSpec的具体实现:
Java的
上述代码根据父类的MeasureSpec和自身的的LayoutParams建立子元素的MeasureSpec,具体过程同窗们自行分析,最终的建立规则以下表:
ViewGroup中在遍历完子视图后,须要根据子元素的测量结果来决定本身最终的测量大小,并调用setMeasuredDimension方法保存测量宽高值。
Java的
这里调用了resolveSizeAndState来肯定最终的大小,主要是保证测量的大小不能超过父容器的最大剩余空间maxWidth,这里咱们看看它里面的实现:
Java的
关于具体的ViewGroup的onMeasure过程这里不作分析,因为每种布局的测量方式不同,不可能逐个分析,但在它们的onMeasure里面的步骤是有必定规律的:
1.根据各自的测量规则遍历儿童元素,调用getChildMeasureSpec方法获得孩子的measureSpec;
2.调用儿童的度量方法;
3.调用setMeasuredDimension肯定最终的大小。
查看的措施
查看的测量过程由其测量方法来完成,测量方法是一个最终的类型的方法,这意味着子类不能重写此方法,在景观的措施方法里面会去调用onMeasure方法,咱们这里只要看onMeasure的实现便可,以下:
Java的
代码很简单,咱们继续看看getDefaultSize方法的实现:
Java的
从上述代码能够得出,景观的宽/高由specSize决定,直接继承视图的自定义控件须要重写onMeasure方法并设置WRAP_CONTENT时的自身大小,不然在布局中使用WRAP_CONTENT就至关于使用match_parent。
上述就是查看的量度大体过程,在测量完成以后,经过getMeasuredWidth /高度方法就能够得到测量后的宽高,这个宽高通常状况下就等于查看的最终宽高了,由于搜索的布局布局的时候就是根据measureWidth /高度来设置宽高的,除非在布局中修改了测量值。
布局布局
布局的做用是一个ViewGroup用来肯定子元素的位置,当ViewGroup中的位置被肯定后,它在onLayout中会遍历全部的子元素并调用其布局方法。简单的来讲就是,布局方法肯定视图自己的位置,而onLayout方法则会肯定全部子元素的位置。
先看看查看的布局方法:
因微信字数限制,请点击原文连接查看完整内容
总结
到这里,查看的措施,布局,绘制三大流程就说完了,这里作一下总结: