view的视图有两种情况:
- 内容型视图:由视图的内容决定其大小。
- 图形型视图:父视图为view动态调整大小。
### measure的本质
把视图布局使用的“相对值”转化成具体值的过程,即把WRAP_CONTENT,MATCH_PARENT转化为具体的值。
measure内部的设计思路
再来看一下View中measure()函数原型:
public final void measure(int widthMeasureSpec, int heightMeasureSpec);
当父视图对子视图进行measure操作时,会调用子视图的measure()方法。该函数的意思是父视图为子视图所提供的measure的”规格”,因为父视图最终为子视图提供的”窗口”大小是由父视图和子视图共同决定的。该值有32位组成,高16位保存的是specMode, 低16位保存spcMode。
spceMode有三种:
- MeasureSpec.EXACTLY: “确定的”, 父视图希望子视图的大小应该是spec中指定的。在一般情况下, View的设计者应该遵守指示,将View的measureHeight和measuredWidth设置成指定的值。
- MeasureSpec.AT_MOST:”最多”,子视图最多是specSize中指定的值。
- MeasureSpec.UNSPECIFIED: “没有限制”, 此时View的设计者可以根据自身的特性设置视图的大小。
以上介绍measureSpec的语义,该参数是父视图传递给子视图的,看一下measureSpec是如何产生的:
ViewRoot中,调用host.measure()函数,参数分别是局部变量childWidthMeasureSpec和childHeightMeasureSpec,这两个变量的赋值最初是通过调用getRootMeasureSpec()函数获得的:
childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
childHeightMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.height);
ViewGroup中的measureChildWidthMargins()
- 调用child.getLayoutParams()获得子视图的LayoutParams属性。
- 调用两次getChildMeasureSpec()函数,分别计算出该子视图的宽度和高度的spec。
- 调用child.measure()函数。子视图可以重载onMeasure()函数,并调用setMeasureDimension()函数设置任意大小的布局,这将成为子视图的最终布局大小。