LinearLayout.onMeasure-获取子View总高度

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

  1. 获取子View的引用
  2. 判断子View是否为空,或者是否为GONE,如果是的话,则开始下一轮循环
  3. 判断这个子View上面是否要显示Divider,如果有的话再加上Divider的高度
  4. 拿到子View的LayoutParams,这个东西在XML解析或者在addView的时候就会被设置到子View上
  5. 拿到LayoutParams中的weight属性,加到totalWeight上,后面如果mWeightSum没有被赋值的话,就会用到这个totalWeight来计算多余的空间分配
  6. 判断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了
  7. 如果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
  8. 设置完lp.height之后,就会调用measureChildBeforeLayout,获取到ChildeMeasureSpec之后,调用child.measure开始测量子View
  9. 测量完之后,再把oldHeight重新赋值给lp.height
  10. 重新将mTotalLength重新赋值,赋值为mTotalHeight+childHeight+子View的上下Margin
  11. 判断useLargestChild,如果true的话,那么largestChildHeight的值为Math.max(childHeight,largestChildHeight)
  12. 如果设置了baselineChildIndex的话,那么判断是否是当前的子View,如果是的话,那么mBaselineChildTop就被赋值为mTotalLength,之后进行layout的时候会要用到mBaselineChildTop来进行子View的位置计算
  13. 如果widthMode不为MeasureSpec.EXACTLY,并且lp.width为LayoutParmas.MATCH_PARENT,matchWidth和matchWidthLocally都设置成true
  14. 获取子View测量过的width以及左右的margin,通过combineMeasuredState重新计算childState
  15. 将allFillParent进行赋值,判断之前的allFillParent如果不为true而且lp.width为LayoutParmas.MATCH_PARENT的话,那么就会赋值为true
  16. 如果lp.weight>0的话,那么就将weightedMaxWidth进行赋值,否则的话alternativeMaxWidth就会被进行赋值

你可能感兴趣的:(LinearLayout.onMeasure-获取子View总高度)