MeasureSpec:
MeasureSpec代表一个32位的int值,高2位代表SpecMode,低30位代表SpecSize,在很大程度决定一个View的规格。
- 其中SpecMode是指测量模式,SpecSize是指某种测量模式下的规格大小。
- SpecMode和SpecSize也是int值,它们可以打包为MeasureSpec
public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,@MeasureSpecMode int mode) {
if (sUseBrokenMakeMeasureSpec) {
return size + mode;
} else {
return (size & ~MODE_MASK) | (mode & MODE_MASK);
}
}
- MeasureSpec可以解包为它们:
@MeasureSpecMode
public static int getMode(int measureSpec) {
//noinspection ResourceType
return (measureSpec & MODE_MASK);
}
public static int getSize(int measureSpec) {
return (measureSpec & ~MODE_MASK);
}
SpecMode有三个类型:
- UNSPECIFIED:父容器不对View有任何限制,一般用于系统内部。
- EXACTLY:父容器已经检测出View所需要的精确大小。它对应于LayoutParams中的match_parent和具体的数值这两种模式。
AT_MOST:父容器制定一个大小,View的大小不能大于这个值,它对应于wrap_content。
LayoutParams和父容器一起决定View的MeasureSpec:
这里主要是LayoutParams与MeasureSpec的关系:
通过查看ViewGroup的measureChildWithMargin方法和getChildMeasureSpec可知:- 根据父容器的MeasureSpec同时结合View本身的LayoutParams来确定子元素的MeasureSpec
子元素的可用大小为父容器的尺寸减去padding
普通View的MeasureSpec的创建规则
(不包括UNSPECIFIED)
- 如果View采用的是固定宽高(dp/dx),则无论父容器的MeasureSpec是什么,View的MeasureSpec都会是精确模式。
- 如果View的宽高为match_parent,(1)如果父容器为精准模式(EXACTLY),那么view的大小是精准模式且其大小为父容器的剩余空间;(2)如果父容器为最大模式(AT_MOST),,那么view的大小是最大模式且其大小不会超过父容器的剩余空间
- 如果View的宽高为wrap_content,则无论父容器是精准模式还是最大模式,它都是最大模式且大小不会超过父容器的剩余空间。