问题1 :view 测量模式
我们一起来看看大家对这个知识的掌握程度吧。
在早期的博客的里面,很多时候,见到有如下的介绍:
- 如果你的 View 设置了 match_parent,则在onMeasure 中得到的测量模式为:EXACTLY;
- 如果设置了 wrap_conent,则对应测量模式为:AT_MOST;
- 还剩下一个 UNSPECIFIED大家不用管,不常用;
上述描述每句话都可以认为是错的
自定义ViewGroup过程中,需要在onMeasure里面对子View进行测量。
调用ViewGroup的静态方法getChildMeasureSpec来直接获取目标子View的MeasureSpec,然后手动measure(比如ScrollView、NestedScrollView、DrawerLayout、TabLayout、ConstraintLayout)。
其实,measureChild和measureChildWithMargins里面也是会通过getChildMeasureSpec方法来获取MeasureSpec的,也就是说,上面提到的这些容器,在测量它们的子View之前,都是先通过getChildMeasureSpec方法来获取子View的宽高MeasureSpec,然后传给子View的measure方法的。
好,那我们现在来看看getChildMeasureSpec方法里面做了什么:
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
int specMode = MeasureSpec.getMode(spec);
......
switch (specMode) {
case MeasureSpec.EXACTLY:
if (childDimension >= 0) {
......
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == ViewGroup.LayoutParams.MATCH_PARENT) {
......
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == ViewGroup.LayoutParams.WRAP_CONTENT) {
......
resultMode = MeasureSpec.AT_MOST;
}
break;
case MeasureSpec.AT_MOST:
if (childDimension >= 0) {
......
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == ViewGroup.LayoutParams.MATCH_PARENT) {
......
resultMode = MeasureSpec.AT_MOST;
} else if (childDimension == ViewGroup.LayoutParams.WRAP_CONTENT) {
......
resultMode = MeasureSpec.AT_MOST;
}
break;
case MeasureSpec.UNSPECIFIED:
if (childDimension >= 0) {
......
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == ViewGroup.LayoutParams.MATCH_PARENT) {
......
resultMode = MeasureSpec.UNSPECIFIED;
} else if (childDimension == ViewGroup.LayoutParams.WRAP_CONTENT) {
......
resultMode = MeasureSpec.UNSPECIFIED;
}
break;
}
return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
} 可以看到:
在父容器的specMode为EXACTLY时,一切正常(子View尺寸指定为match_parent或精确的dimen值时,Mode = EXACTLY,尺寸指定为wrap_content则Mode = AT_MOST);
当父容器specMode为AT_MOST的时候,呵呵,可以看到,除了指定了dimen值之外,无论设置为match_parent或wrap_content,Mode最终都是会变成AT_MOST;
如果父容器specMode是UNSPECIFIED的话,跟上面的逻辑差不多,都是会变成UNSPECIFIED的,除非指定了精确的dimen值;
所以,View的onMeasure方法中收到的宽高MeasureSpec,不完全是由xml布局中设置的宽高或LayoutParams的宽高值决定的。
结论就是:
它自身的LayoutParams设置的值 + 父容器的测量模式来决定的。
- 本文作者: 风追着云
- 本文链接: https:/github.com/tuyrt7/tuyrt7.github.io/2020/03/31/开发常见-问题/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!

SongTaste