我留下了比较重要的三个方法:
- makeMeasureSpec。用于生成一个MeasureSpec,生成的方式就是size+mode,得到一个32位的int值。
- 获取mode。也就是取前2位的值作为mode。
- 获取size。也就是取后30位的值作为size。
至此,我们至少知道了MeasureSpec是一个32位的int值,高2位为mode(测量模式),低30位为size(测量大小)。
这么做的目的主要是避免过多的对象内存分配。
所以我们可以大致猜测,这个MeasureSpec就是用来标记View的测量参数,其中测量模式可能和View具体怎么显示有关,而测量大小就是值的View实际大小。
当然,这只是我们的初步猜测。
要搞清楚具体信息,就要从View树的绘制测量开始说起。
DecorView的测量
上文说到,测量代码是从ViewRootImpl的measureHierarchy开始的,然后会执行到performMeasure方法:
- private void measureHierarchy(){
- childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
- childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
- performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
- }
- private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
- try {
- mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
- }
很明显,在这里就会进行第一次MeasureSpec的计算,并且传给了下层的mView,也就是DecorView。
那我们就来看看DecorView的MeasureSpec测量规格计算方式:
- private static int getRootMeasureSpec(int windowSize, int rootDimension) {
- int measureSpec;
- switch (rootDimension) {
- case ViewGroup.LayoutParams.MATCH_PARENT:
- // Window can't resize. Force root view to be windowSize.
- measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
- break;
- case ViewGroup.LayoutParams.WRAP_CONTENT:
- // Window can resize. Set max size for root view.
- measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
- break;
- default:
- // Window wants to be an exact size. Force root view to be that size.
- measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
- break;
- }
- return measureSpec;
- }
所以DecorView是和它的LayoutParams有关,其实也就是跟Window的调整有关,如果Window是子窗口,那么就可以调整,比如Dialog的宽高设置为WRAP_CONTENT,那么DecorView对应的测量规格就是AT_MOST。
到此,我们也可以初步得到这个测量规格mode的含义:
- 如果View的值是确定大小,比如MATCH_PARENT或者固定值,那么它的测量模式就是MeasureSpec.EXACTLY。
- 如果View的值是自适应,比如WRAP_CONTENT,那么它的测量模式就是 MeasureSpec.AT_MOST。
具体是不是这样呢?我们继续到下层View一探究竟。
View/ViewGroup的测量
对于具体的View/ViewGroup 测量,就涉及到另外的一个方法measureChildWithMargins,这个方法也是在很多布局中会看到,比如LinearLayout。