文章翻译自How Android Draws Views
使用MarkDown编辑,根据自己的理解翻译Android Developer,深知有很多地方语序逻辑不当,希望能不断提升。翻译不当的地方,望指正
当一个Activity获取到焦点,他会要求绘制它的布局。Android framework 会处理绘制的程序,但是Activity必须要提供布局层级结构的根节点。
绘制从布局的根节点开始。要求测量和绘制布局树。绘制是通过遍历树和渲染每个相交在无效区域的视图。反过来,每个
ViewGroup
负责要求他的每个子视图去绘制,每个视图负责自己的绘制。因为树是按顺序遍历的,说明父节点会比子节点先被绘制,同级的节点根据他们出现的顺序来绘制。
绘制布局有两个过程:一个
measure
过程,一个
layout
过程。这个
measure
过程由
measure(int, int)
执行,在视图树中是由上到下遍历。在递归中每个视图传递他的尺寸规格。在
measure
的最后,每个视图都保存了他的尺寸值。第二部分发生在
layout(int, int, int, int)
也是从上到下的。在这个环节中,每个父节点都根据上一部每个空间计算的尺寸来负责布局子控件的位置。
当每一个视图的
measure()
方法返回时,他的
getMeasuredWidth()
和
getMeasuredHeight()
的值已经设定好了,以及这些视图的子节点。一个视图的测量出的高宽必须遵守他的父节点的限制。这个保证在测量的最后,所以的父节点可以包含所有子节点的测量值。一个父视图可能要调用多次
measure()
方法。比如父视图可能要测量每个没有确定尺寸的子视图,来决定他们应该有多大,如果子节点不受限的尺寸和太大或太小(如果子节点不同意他们各自获取到的空间,父控件在第二部分会干预和设置规则),父节点会再次调用
measure()
方法
测量过程使用两个类来和尺寸交互。视图对象使用
ViewGroup.LayoutParams
类来告诉他的父控件他们想如何被测量和摆放。
ViewGroup.LayoutParams
最基础的类只能描述每个视图的高宽。对于每个尺寸,可以确定如下一种方式:
- 一个确定的数
-
:表示这个视图想和他的父控件一样大MATCH_PARENT
-
:表示这个视图刚刚可以包住他的内容大小WRAP_CONTENT
- 对于
不同的子类,ViewGroup
有子类相对应,比如,ViewGroup.LayoutParams
有属于他的RelativeLayout
,有能力让子视图垂直居中或者水平居中。ViewGroup.LayoutParams
MeasureSpec
测量要求从父控件传达给子控件。一个
MeasureSpec
可以是如下三个模式的一个:
-
:这个由父视图来决定子视图的理想尺寸。比如,一个UNSPECIFIED
在他的子视图中调用LinearLayout
,长度用的measure()
, 宽度用UNSPECIFIED
240,表示想知道这个视图如果宽度是240ps,那么应该给多高呢?EXACTLY
-
这个表示父控件给子控件强制加上一个具体的尺寸,子控件必须使用这个尺寸,保证所有的子孙控件都要在这个尺寸里面。EXACTLY:
-
这个表示父控件给子控件加上一个最大的尺寸。子控件必须保证所有的子孙控件毒药在这个尺寸里面。AT MOST: