View的getWidth和getHeight,getMeasuredWidth和getMeasuredHeight是在view放到layout中显示的时候才能获得正确的值的,但是往往我们需要在它显示之前就知道它的大小是多少,宽高是多少。怎么实现呢?我们需要预估View的宽高。
其实在View显示出来之后再获取它的宽高时能正确的得到它的大小,android绘制view的过程简单描述可以解释为:
计算大小(measure)、布局坐标计算(layout)、绘制到屏幕(draw);
第一步:
当activity启动时,初始化view,由Window对象DecorView调用View对象的public final void measure(int widthMeasureSpec, int heightMeasureSpec)方法开始。
第二步:
View的measure方法onMeasure(widthMeasureSpec, heightMeasureSpec),该方法进行实质性的view大小计算。注意:view的代销是由父view和自己的大小决定的,而不是单一决定的。这也就是为什么viewGroup的子类会重新该方法,比如linearLayout等。因为他们要计算自己和子view的代销。view基类有自己的实现,只是设置大小。其实根据源码来看,measure的过程本质就是把Match_parent和wrap_content转换为实际大小。
第三步:
当measure计算大小完成后,开始调用view的public final void layout(int l, int t, int r, int b),viewGroup将此方法abstract了,所以我们继承viewGroup的时候,需要重新该方法。该方法的实质是通过measure计算好的大小,计算出view在屏幕上的坐标点。
第四步:
measure完成了,layout过了,那么就要开始会知道屏幕上了,所以开始调用view的 public void draw(Canvas canvas)方法,此方法可以重写,自定义view的绘制。
1.一个是measure();
2.一个是requestLayout();
View.measure()方法的原型如下:
View.measure(widthMeasureSpec, heightMeasureSpec)它的两个参数是两个可以经过计算获得的MeasureSpec值,不需要时可以传两个0.
通过下面的方法可以计算得到MeasureSpec值:
View.MeasureSpec.makeMeasureSpec(maxW, View.MeasureSpec.AT_MOST)
这个方法的两个参数:
第一个参数表示父View中允许这个子View占用的宽/高;
第二个参数是模式,它有三种选择:
UNSPECIFIED:不限定;
EXACTLY:固定,确定大小;
AT_MOST:最多,最大大小。