View测量大小的影响因素汇总
程序员文章站
2022-05-27 11:51:40
...
之前面试的时候遇到一道问题,父View的属性(match_parent和wrap_content)对测量子view的影响,当时很蒙,没有回答上来,最近在看View源码的时候发现里面早已给出了标准答案,
先上源码
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
//父View的宽/高测量模式
int specMode = MeasureSpec.getMode(spec);
//父View的宽/高大小
int specSize = MeasureSpec.getSize(spec);
//父View剩下的可用区域
int size = Math.max(0, specSize - padding);
int resultSize = 0;
int resultMode = 0;
switch (specMode) {
//父View_EXACTLY
case MeasureSpec.EXACTLY:
//如果子View写si了宽/高
if (childDimension >= 0) {
//子View的MeasureSpec=EXACTLY+写si的宽/高(si说多了不吉利)
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
//子View的MeasureSpec=EXACTLY+父View剩下的区域
resultSize = size;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
}
break;
//父View_AT_MOST
case MeasureSpec.AT_MOST:
//如果子View写死了宽高
if (childDimension >= 0) {
//子View的MeasureSpec=EXACTLY+写si的宽/高
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
//子View的MeasureSpec=AT_MOST+父View剩下的区域
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
}
break;
//父View_UNSPECIFIED从来没有用到,不做分析
case MeasureSpec.UNSPECIFIED:
if (childDimension >= 0) {
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
resultMode = MeasureSpec.UNSPECIFIED;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
resultMode = MeasureSpec.UNSPECIFIED;
}
break;
}
return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}
从源码中不难看出,子View固定宽高:测量模式不受父View影响,全都为EXACTLY,宽高固定。
当子View没有固定宽高:如果父View都为AT_MOST,子View想都别想还是为AT_MOST,如果父View为EXACTLY且子View的LayoutParams为match_parent,才为EXACTLY。宽高都为父View剩下的区域。这就很好的明白了为什么我们自定义View时,如果没对View的宽高进行处理,View即使是wrap_content也会撑满整个屏幕了。
综上可以得出结论:
父View在帮助计算子View的MeasureSpec时有着固定的套路:
1.受父View的MeasureSpec影响
2.受子View自身的LayoutParams影响
3.计算父View剩下可用的区域,减去父View的padding和子View的margin距离和父View已经使用(预定)的区域大小。
参考文档:
https://blog.csdn.net/sinat_35938012/article/details/81055380