子View的MeasureSpec的值是由(子View的布局参数(LayoutParams)和父容器的MeasureSpec值)计算得来的,具体逻辑
/* * @param spec 父View的详细测量值 * @param padding View当前尺寸的内边距和外边距 * @param childDimension 子视图的布局参数 * @return a MeasureSpec integer for the child */ public static int getChildMeasureSpec(int spec, int padding, int childDimension)
根据View的类型measure过程主要分为两种情况
(1)单一View的measure过程
1. measure过程:该方法被final修饰,不可以被覆写
基本测量逻辑的判断(先判断是否是强制测量、测量模式改变了没有,再判断是否强制测量、忽略缓存)
if (是否强制测量 || 是否需要重新测量(测量模式有没有改变)) {
if (mMeasureCache缓存中没有取到值 || 是否忽略缓存) {
onMeasure();
}
}
2. onMeasure()过程:
setMeasureDimension()
getDefaultSize()
getSuggestedMinimumWidth()
因此:在自定义控件时候,如果没有重写onMeasure方法,同时给控件设置wrap_content属性时,控件默认会显示match_parent效果。
其中:
mMeasureCache中存储通过传入的widthMeasureSpec和heightMeasureSpec计算得出的key值信息,即view的信息。
(long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;)
mPrivateFlags用于记录了View的各种状态位。
(2)ViewGroup的measure过程
1. measureChildren()
for (遍历ViewGroup中的所有子View) {
if (View不是GONE状态) {
measureChild()
}
}
2. measureChild()
measureSpec = 通过getChildMeasureSpec()方法获取到当前Child的MeasureSpec的值
measure(measureSpec);
3. getChildMeasureSpec() 根据父布局的MeasureSpec和当前View的尺寸决定当前View的MeasureSpec
4. measure()
单一View的measure过程与ViewGroup过程最大的不同:单一View对onMeasure()具有统一的实现,而ViewGroup没有
若LinearLayout的子View设置了weight,会进行两次measure计算,会比较耗时,所有当LinearLayout的子View需要使用weight的时候,最好替换成RelativeLayout布局