当Acticity接收到焦点后, 它会请求绘制布局。Android框架负责处理绘制的过程,但Activity必须提供布局层次的根节点。
绘制从布局的根节点处开始。它被请求度量和绘制布局树。绘制会在树中游走并在无效区域渲染视图。依次的,每个视图组负责请求每个子视图绘制(用draw()方法),每个视图负责绘制自身。因为这个树是按一定顺序生长的,所以父视图会比它们的孩子视图先(或后)绘制,兄弟视图之间就按照它们在树中出现的顺序来绘制。
注:框架不会在无效区域(invalid region)以外的地方绘制视图,并且在后台小心翼翼的为你绘制。你可以强制绘制视图,调用invalidate().
Linc注:这个无效区域是什么意思,我在网上搜了一下,并没用明确的答案,希望有知道的大侠可以告知。上面的意思是只能在这个区域绘制视图。那么是不是就可以这样理解,这个区域是专门用来绘制视图的区域?那么如何获得呢?
绘制布局要分为两个过程:度量和布局。度量(measuring)调用measure(int, int)方法来实现并且它也是从上到下遍历视图树。每个视图在递归的时候从树上向下依次度量它的尺寸。在度量的最后,每个视图都会存储它的度量值。第二个过程也是从上到下,调用layout(int, int,int, int)来进行。在这个过程每个父亲视图负责用度量阶段计算的大小值来定位(配置)它们的孩子视图。
当视图的measure方法返回时,必须要设置它们的getMeasuredWidth()和getMeasuredHeight()的值及所有它们的子节点(descendants)。一个视图度量的宽和高的值必须要遵守它的父亲视图的约束,并不是随意设定的。这样就保证在度量的最后,每个父亲都接受它们的孩子的度量值。一个父亲视图可能不止一次的在其孩子上调用measure()方法。举个例子,父亲在没有找到它们想要的度量值时,如果孩子的度量值的和太大或太小,会再次调用measure度量每个孩子(如果孩子不同意它们获得的空间时,父亲将会介入(intervene)并在第二阶段设置规定)。
注:初始化布局,要调用requestLayout()。在视图确信在当前边界已不再适合时调用此方法。
度量阶段使用两个类来交流视图的大小。View.MeasureSpec类是视图用来告知它们的父亲它们想要度量和定位的。LayoutParams基类只是描述视图想要它的宽和高到底多大。对每个尺寸,它可以指定下面的其中一个:
1、 一个确切值
2、 FILL_PARENT,这意味着它想和父亲一样大小
3、 WRAP_CONTENT,这意味着它只想要能满足自己的内容的大小
对不同的ViewGroup的子类都会有相应的LayoutParams子类。例如,RelativeLayout有自己的LayoutParams子类,它包含设置子视图在水平和垂直中央的能力。
MeasureSpecs用来从树上到树下发送请求给父视图及子视图。MeasureSpec可以是下面三种模式的一种:
1、 UNSPECIFIED:
子视图可以自己确定大小。例如,LinearLayout可能调用measure()方法在子视图的高设置UNSPECIFIED和宽为EXACTLY240时,子视图的高可以自己设定,宽为240像素。
2、 EXACTLY:
父视图强制为子视图设置一个值,子视图必须使用这个大小并且其后代视图一定要在这个值的范围内。
3、 AT_MOST:
父视图为子视图设置一个最大值。子视图必须要遵守它和它的后代视图的大小都在最大值以内。