当Activity获取焦点的时候,它就需要绘制布局。Android框架会处理绘制过程,但这个Activity必须提供它布局树的根节点。
绘制过程是从布局的根节点开始的。这个过程需要测量和绘制布局树。绘制过程是通过遍历树和渲染每个与绘制区域相交的视图来处理的。接下来,ViewGroup职责就是请求它的每个子视图都会绘制(使用draw()方法),同时View的职责就是绘制自身。由于这个树都是依序遍历,这就意味着这个父视图会在子视图之前绘制,并且会按照出现在树中的顺序绘制它们的兄弟姐妹。
框架不会绘制不在绘制区域的视图对象,并且它也为你提供后台绘制视图的功能。通过调用invalidate(),你可以强制绘制视图。
绘制布局有两个过程:measure过程和layout过程。测量过程是通过measure(int,int)来实现的,是一种自上而下的遍历过程。在遍历期间,每个视图都会传递尺寸说明到下面的树中。在测量过程结束时,每个视图都存储了它的测量值。第二个过程是由layout(int,int,int,int)触发,也是一种自上而下的过程。在这个过程中,父视图的责任是使用测量过程计算出来的尺寸来放置它的所有子视图。
当视图对象的measure()返回时,它的getMeasuredWidth()和getMeasuredHeight()方法是肯定有值的,它的所有后代视图也一样。视图对象测量后的宽度和高度必须受到视图对象父视图的约束。这就保证了在测量过程结束时,所有父视图都会接受它们子视图的测量值。父视图可能在它的子视图上调用一次以上的measure(int,int)方法。例如,父视图可以使用unspecified
dimensions来将它的每个子视图都测量一次来算出它们到底需要多大尺寸,如果所有这些子视图没被限制的尺寸的和太大或太小,那么它会用精确数值再次调用measure()(也就是说,如果子视图不满意它们获得的区域大小,那么父视图将会干涉并设置第二次测量规则)。
为了发起一次布局,需要调用requestLayout()。当视图确信不再调整分配给它的区域时,这个方法就会由视图自己调用。
测量过程使用两个类来传递尺寸。视图对象使用ViewGroup.LayoutParams类告诉父视图它们想如何被测量和放置。基本的ViewGroup.LayoutParams类只描述了视图需要多大的宽和高。它可以用下面当中的任意一个指定尺寸:
1.确切数字
2.MATCH_PARENT,意味着这个视图需要和它父视图一样大的尺寸(减去padding)
3.WRAP_CONTENT,意味着这个视图需要足够装下内容的尺寸(加上padding)
有针对不同ViewGroup子类的ViewGroup.LayoutParams子类。例如,RelativeLayout有它自己的ViewGroup.LayoutParams子类,它包含让子视图横向和垂直居中的能力。