整个View树的绘图流程是在ViewRoot.java类的 performTraversals() 函数展开的,该函数做的执行过程可简单概况为:
该函数做的执行过程可简单概况为根据之前设置的状态,判断是否需要重新计算视图大小(measure)、是否重新需要安置视图的位置(layout)、以及是否需要重绘 (draw),
其框架过程如下:
一、measure测三围
主要作用:
为整个View树计算实际的大小,即设置实际的高(对应属性:mMeasuredHeight)和宽(对应属性:mMeasureWidth),每个View 的控件的实际宽高都是由父视图和本身视图决定的。
具体的调用链如下:
ViewRoot根对象的属性mView(其类型一般为ViewGroup类型)调用measure()方法去计算View树的大小,回调View/ViewGroup 对象的onMeasure()方法,该方法实现的功能如下:
1、设置本View 视图的最终大小,该功能的实现通过调用 setMeasuredDimension()方法去设置实际的高(对应属性:mMeasuredHeight)和宽(对应属性:mMeasureWidth)。
2 、如果该View 对象是个ViewGroup类型,需要重写该onMeasure()方法,对其子视图进行遍历的measure() 过 程 。对 每 个 子 视 图 的 measure() 过 程 , 是 通 过 调 用 父 类 ViewGroup.java 类 里 的 measureChildWithMargins()方法去实现,该方法内部只是简单地调用了 View 对象的 measure()方法。
二、layout摆好姿势
主要作用:
为将整个根据子视图的大小以及布局参数将 View树放到合适的位置上。
具体的调用链如下:
1、layout 方法会设置该 View 视图位于父视图的坐标轴,即 mLeft,mTop,mLeft,mBottom(调用setFrame()函数去实现)接下来回调onLayout()方法(如果该View 是ViewGroup对象,需要实现该方法,对每个子视图进行布局)。
2、如果该View 是个ViewGroup类型,需要遍历每个子视图 childView,调用该子视图的 layout()方法去设置它的坐标值。
三、draw挥洒激情
由ViewRoot对象的performTraversals()方法调用draw()方法发起绘制该View 树,值得注意的是每次发起绘图时,并不会重新绘制每个View树的视图,而只会重新绘制那些“需要重绘”的视图,View 类内部变量包含了一个标志位DRAWN,当该视图需要重绘时,就会为该View添加该标志位。
调用流程 :
1 、绘制该View 的背景
2 、为显示渐变框做一些准备操作(大多数情况下,不需要改渐变框)
3、调用onDraw()方法绘制视图本身(每个View 都需要重载该方法,ViewGroup不需要实现该方法)
4、调用dispatchDraw ()方法绘制子视图(如果该 View 类型不为ViewGroup,即不包含子视图,不需要重载该方法)
值得说明的是,ViewGroup类已经为我们重写了dispatchDraw ()的功能实现,应用程序一般不需要重写该方法,但可以重载父类函数实现具体的功能。