How Android Draws Views
When an Activity receives focus, it will be requested to draw its layout. The Android framework will handle the procedure for drawing, but the Activity must provide the root node of its layout hierarchy.
Drawing begins with the root node of the layout. It is requested to measure and draw the layout tree. Drawing is handled by walking the tree and rendering each View that intersects the invalid region. In turn, each View group is responsible for requesting each of its children to be drawn (with the draw()
The framework will not draw Views that are not in the invalid region, and also will take care of drawing the Views background for you.
You can force a View to draw, by calling
.invalidate()
Drawing the layout is a two pass process: a measure pass and a layout pass. The measuring pass is implemented in measure(int, int)
layout(int, int, int, int)
When a View's measure()
getMeasuredWidth()
getMeasuredHeight()
measure()
measure()
To initiate a layout, call
. This method is typically called by a View on itself when it believes that is can no longer fit within its current bounds.requestLayout()
The measure pass uses two classes to communicate dimensions. The View.MeasureSpec
- 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, RelativeLayout has its own subclass of LayoutParams, which includes the ability to center child Views horizontally and vertically.
MeasureSpecs are used to push requirements down the tree from parent to child. A MeasureSpec can be in one of three modes:
- UNSPECIFIED: This is used by a parent to determine the desired dimension of a child View. For example, a LinearLayout may call
measure()
on its child with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how tall the child View wants to be given a width of 240 pixels. - EXACTLY: This is used by the parent to impose an exact size on the child. The child must use this size, and guarantee that all of its descendants will fit within this size.
- AT_MOST: This is used by the parent to impose a maximum size on the child. The child must guarantee that it and all of its descendants will fit within this size.
当Activity得到焦点后,就被要求画出它的布局。Android框架
负责绘画的整个过程,但Activity必须提供布局的根结点。
绘画从根结点开始,它必须测量和画出布局树。 Drawing is handled by walking the tree and rendering each View that intersects the invalid region。
反过来,每一个ViewGroup负责请求每个子View去出它自己(用draw())
,每一个子View负责把自己画出来。因为布局树从上到下依次访问,因
此父结点先被画出来,兄弟结点再根据它们在树中出现的顺序,依次
画出来。
画布局包括两个过程:测量过程和布局过程。测量过程在measure(int,int)
方法中实现。并且从布局树的根结点到子孙结点。在自顶向下的递归过程
中,每一个View都保存了自己的尺寸。第二个过程在layout(int, int ,
int, int) 中实现,同样也是自顶向下调用。在这个过程中,父结点
利用在测量过程中得到的尺寸来布局子结点。
当View的measure()方法返回时,它的getMeasuredWidth()和
getMeasuredHeight()的值必须被设定,以给它的子孙使用。
子结点的measure width 和height必须严格限制在父结点的范围内
。父结点可能调用measure()方法很多次。有不同的用途,主要是协调
实际尺寸和子结点的尺寸。
测量过程利用两个类来交流尺寸信息。类View.MeasureSpec被View用来通知
它的父结点,它想怎样来设定尺寸和定位。基本的LayoutParams类只是被
用来简单地描述想把宽和高设定为多大。对于每一个尺寸,可以设定为下面
3种中的一个:
1.一个确定的数值。
2.FILL_PARENT。这意味着View想设定为同它的父结点一样大(减去边界)。
3.WRAP_CONTENT。这意味着View只想把大小设定为正好包含住自己的内容(加
上边界;
每一个ViewGroup类有相应的LayoutParams子类,用来描述它的尺寸和定位信息。例如,RelativeLayout类有它自己的Layoutparams来使它的子结点View在水平
和垂直方向居中。
MeasureSpec被用来自顶向下(通过View tree)传递各种尺寸和定位需求。
每一个MeasureSpec能够是下列3种模型中的一个:
1.UPSPECIFIED。
2.EXACTLY。
3.AT_MOST。