onMeasure调用次数
当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子类,它包含让子视图横向和垂直居中的能力。
传送门:《Android -- MeasureSpec》http://www.cnblogs.com/yydcdut/p/4170629.html
onMeasure和onLayout
在继承ViewGroup类时,需要重写两个方法,分别是onMeasure和onLayout。
1,在方法onMeasure中调用setMeasuredDimension方法
void setMeasuredDimension(int measuredWidth, int measuredHeight)
在onMeasure(int, int)中,调用setMeasuredDimension(int width, int height)来存储测量得到的宽度和高度值。
2,在方法onMeasure中调用孩子的measure方法
void measure(int widthMeasureSpec, int heightMeasureSpec)
这个方法用来测量出view的大小。父view使用width参数和height参数来提供constraint信息。实际上,view的测量工作在onMeasure(int, int)方法中完成。因此,只有onMeasure(int, int)方法可以且必须被重写。参数widthMeasureSpec提供view的水平空间的规格说明,参数heightMeasureSpec提供view的垂直空间的规格说明。
3,解析onMeasure(int, int)方法
void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
测量view及其内容来确定view的宽度和高度。这个方法在measure(int, int)中被调用,必须被重写来精确和有效的测量view的内容。
view的基本测量数据默认取其背景尺寸,除非允许更大的尺寸。子view必须重写onMeasure(int, int)来提供其内容更加准确的测量数值。如果被重写,子类确保测量的height和width至少是view的最小高度和宽度(通过getSuggestedMinimumHeight()和getSuggestedMinimumWidth()获取)。
4,解析onLayout(boolean, int, int, int, int)方法
void onLayout(boolean changed, int l, int t, int r, int b)
调用场景:在view给其孩子设置尺寸和位置时被调用。子view,包括孩子在内,必须重写onLayout(boolean, int, int, int, int)方法,并且调用各自的layout(int, int, int, int)方法。
参数说明:参数changed表示view有新的尺寸或位置;参数l表示相对于父view的Left位置;参数t表示相对于父view的Top位置;参数r表示相对于父view的Right位置;参数b表示相对于父view的Bottom位置。