for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
if (child == null) {
mTotalLength += measureNullChild(i);
continue;
}
if (child.getVisibility() == View.GONE) {
i += getChildrenSkipCount(child, i);
continue;
}
if (hasDividerBeforeChildAt(i)) {
mTotalLength += mDividerHeight;
}
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
totalWeight += lp.weight;
if (heightMode == MeasureSpec.EXACTLY && lp.height == 0 && lp.weight > 0) {
// Optimization: don't bother measuring children who are going to use
// leftover space. These views will get measured again down below if
// there is any leftover space.
final int totalLength = mTotalLength;
mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
} else {
int oldHeight = Integer.MIN_VALUE;
if (lp.height == 0 && lp.weight > 0) {
// heightMode is either UNSPECIFIED or AT_MOST, and this
// child wanted to stretch to fill available space.
// Translate that to WRAP_CONTENT so that it does not end up
// with a height of 0
oldHeight = 0;
lp.height = LayoutParams.WRAP_CONTENT;
}
// Determine how big this child would like to be. If this or
// previous children have given a weight, then we allow it to
// use all available space (and we will shrink things later
// if needed).
measureChildBeforeLayout(
child, i, widthMeasureSpec, 0, heightMeasureSpec,
totalWeight == 0 ? mTotalLength : 0);
if (oldHeight != Integer.MIN_VALUE) {
lp.height = oldHeight;
}
final int childHeight = child.getMeasuredHeight();
final int totalLength = mTotalLength;
mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +
lp.bottomMargin + getNextLocationOffset(child));
if (useLargestChild) {
largestChildHeight = Math.max(childHeight, largestChildHeight);
}
}
/**
* If applicable, compute the additional offset to the child's baseline
* we'll need later when asked {@link #getBaseline}.
*/
if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) {
mBaselineChildTop = mTotalLength;
}
// if we are trying to use a child index for our baseline, the above
// book keeping only works if there are no children above it with
// weight. fail fast to aid the developer.
if (i < baselineChildIndex && lp.weight > 0) {
throw new RuntimeException("A child of LinearLayout with index "
+ "less than mBaselineAlignedChildIndex has weight > 0, which "
+ "won't work. Either remove the weight, or don't set "
+ "mBaselineAlignedChildIndex.");
}
boolean matchWidthLocally = false;
if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.MATCH_PARENT) {
// The width of the linear layout will scale, and at least one
// child said it wanted to match our width. Set a flag
// indicating that we need to remeasure at least that view when
// we know our width.
matchWidth = true;
matchWidthLocally = true;
}
final int margin = lp.leftMargin + lp.rightMargin;
final int measuredWidth = child.getMeasuredWidth() + margin;
maxWidth = Math.max(maxWidth, measuredWidth);
childState = combineMeasuredStates(childState, child.getMeasuredState());
allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
if (lp.weight > 0) {
/*
* Widths of weighted Views are bogus if we end up
* remeasuring, so keep them separate.
*/
weightedMaxWidth = Math.max(weightedMaxWidth,
matchWidthLocally ? margin : measuredWidth);
} else {
alternativeMaxWidth = Math.max(alternativeMaxWidth,
matchWidthLocally ? margin : measuredWidth);
}
i += getChildrenSkipCount(child, i);
}
开始循环遍历所有的子View
- 获取子View的引用
- 判断子View是否为空,或者是否为GONE,如果是的话,则开始下一轮循环
- 判断这个子View上面是否要显示Divider,如果有的话再加上Divider的高度
- 拿到子View的LayoutParams,这个东西在XML解析或者在addView的时候就会被设置到子View上
- 拿到LayoutParams中的weight属性,加到totalWeight上,后面如果mWeightSum没有被赋值的话,就会用到这个totalWeight来计算多余的空间分配
- 判断LinearLayout的MeasureSpecMode是否是MeasureSpec.EXACTLY,也就是父View告诉这个LinearLayout,它有一个指定的大小,并且lp.height为0,但是lp.Weight大于0,那么mTotalLength就会取mTotalLength+lp.topMargin+lp.bottomMargin,也就是加上子View的上下边距,因为如果weight总值大于0的话,那么还会再Measure一次的,如果weight为0的话,那么子View的高度也就是0了
- 如果heightMode不是MeasureSpec.EXACTLY,而lp.height为0,lp.weight>0,那么就把它的lp.height设置成LayoutParams.WRAP_CONTENT。因为如果heightMode是UNSPECIFIED或者AT_MOST的,并且子View希望拉伸到它所有可用的空间,就会把它的lp.height设置成WRAP_CONTENT,以至于让它最后不会让自己的height为0
- 设置完lp.height之后,就会调用measureChildBeforeLayout,获取到ChildeMeasureSpec之后,调用child.measure开始测量子View
- 测量完之后,再把oldHeight重新赋值给lp.height
- 重新将mTotalLength重新赋值,赋值为mTotalHeight+childHeight+子View的上下Margin
- 判断useLargestChild,如果true的话,那么largestChildHeight的值为Math.max(childHeight,largestChildHeight)
- 如果设置了baselineChildIndex的话,那么判断是否是当前的子View,如果是的话,那么mBaselineChildTop就被赋值为mTotalLength,之后进行layout的时候会要用到mBaselineChildTop来进行子View的位置计算
- 如果widthMode不为MeasureSpec.EXACTLY,并且lp.width为LayoutParmas.MATCH_PARENT,matchWidth和matchWidthLocally都设置成true
- 获取子View测量过的width以及左右的margin,通过combineMeasuredState重新计算childState
- 将allFillParent进行赋值,判断之前的allFillParent如果不为true而且lp.width为LayoutParmas.MATCH_PARENT的话,那么就会赋值为true
- 如果lp.weight>0的话,那么就将weightedMaxWidth进行赋值,否则的话alternativeMaxWidth就会被进行赋值