当一个Activity被激活时,它将被要求绘制自身的layout。Android Framework会去处理绘制的过程,但是Activity必须提供其layout结构的根节点(root node)。
实际上就是我们使用setContentView(layoutID)时那个layout id,通过这种方式我们就可以告知系统要显示哪一组View。
绘制过程就是从根节点开始的。而测量和绘制layout tree则是必须的。绘制工作是通过走读layout tree并显示相应的View来完成的(这些View都是在invalid区域的)。按照顺序,每个ViewGroup都会child view(通过draw() method),而这些child view会负责自己绘制自己。由于绘制过程是按照顺序(实际就是我们在layout xml文件声明的顺序)从上到下,从父到子来执行的,所以有可能造成某个后边的View覆盖前边声明的View这种现象。
绘制layout有两个过程:一个过程是测量(measure),另一过程是布局(layout)。测量是通过measure(int, int)方法来执行,并且会遍历我们的view tree。每个View都会去发布它的dimension specifications,并顺着树一直执行下去,这个过程是一个递归的过程。最终,每个View都会存储它的测量信息。第二个过程发生在layout(int, int, int, int)中,也是从上到下的顺序。在这个过程中,parent layout会负责安排child view的position,而这个position就会使用之前测量的View的大小信息。
当一个View的measure() 方法返回时,它的getMeasuredWidth() and getMeasuredHeight()的value就一定会被设置好,相应的它的child views的值也会被设置好。一个View的measured hight和measured width必须符合其parent的要求。这保证了最终的测量结果一定是parent接受的结果。一个parent view可以针对其child view呼叫多次measure() 方法。例如,parent view可以先调用一次measure(),并且不指明尺寸,而看child view的需求。如果发现child的需求超出了parent的要求,那么在使用一次measure(),这次parent就可以指明具体的尺寸了。
Measure过程实际上有两个类在期间起作用。一个是View.MeasureSpec,另一个是LayoutParams。先看看Google是怎么定义MeasureSpec的:
A MeasureSpec encapsulates the layout requirements passed from parent to child. Each MeasureSpec represents a requirement for either the width or the height. A MeasureSpec is comprised of a size and a mode. There are three possible modes:
UNSPECIFIED
The parent has not imposed any constraint on the child. It can be whatever size it wants.
EXACTLY
The parent has determined an exact size for the child. The child is going to be given those bounds regardless of how big it wants to be.
AT_MOST
The child can be as large as it wants up to the specified size.
MeasureSpecs are implemented as ints to reduce object allocation. This class is provided to pack and unpack the <size, mode> tuple into the int.
从这我们可以看出它其中定义的是parenet对child的要求,这其中包含了对height和width的要求。(父亲对孩子有哪些要求就在说明)
而LayoutParams是ViewGroup的nested class。我们来看下Google是怎么说明这个类的:
LayoutParams are used by views to tell their parents how they want to be laid out. See ViewGroup Layout Attributes for a list of all child view attributes that this class supports.
The base LayoutParams class just describes how big the view wants to be for both width and height. For each dimension, it can specify one of:
?an exact number
?FILL_PARENT, which means the view wants to be as big as its parent (minus padding)
?WRAP_CONTENT, which means that the view wants to be just big enough to enclose its content (plus padding)
There are subclasses of LayoutParams for different subclasses of ViewGroup. For example, AbsoluteLayout has its own subclass of LayoutParams which adds an X and Y value.
从这段话中我们可以了解这个LayoutParams类是用于child view向parent view传达自己的意愿的一个东东(孩子想变成什么样就要在这向其父亲说明)。值得注意的是LayoutParams只是一个base class。实际上每个不同的ViewGroup都有自己的LayoutParams子类。