Android LinearLayout(7.1) 源码解析

这一节,将分析LinearLayout的onMeasure和onLayout两个方法
1、onMeasure由measureVertical 和measureHorizontal两个方法组成
2、onLayout由layoutVertical 和layoutHorizontal两个方法组成
下面,只分别分析measureVertical 和onLayoutVertical这两个方法

先来看一下onMeasureVertical

void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
        mTotalLength = 0;
        int maxWidth = 0;
        int childState = 0;
        int alternativeMaxWidth = 0;
        int weightedMaxWidth = 0;
        boolean allFillParent = true;
        float totalWeight = 0;

        final int count = getVirtualChildCount();

        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        boolean matchWidth = false;
        boolean skippedMeasure = false;

        final int baselineChildIndex = mBaselineAlignedChildIndex;        
        final boolean useLargestChild = mUseLargestChild;

        int largestChildHeight = Integer.MIN_VALUE;
        int consumedExcessSpace = 0;

        // See how tall everyone is. Also remember max width.
        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;
            }

            final LayoutParams lp = (LayoutParams) child.getLayoutParams();

            totalWeight += lp.weight;

            final boolean useExcessSpace = lp.height == 0 && lp.weight > 0;
            if (heightMode == MeasureSpec.EXACTLY && useExcessSpace) {
                // Optimization: don't bother measuring children who are only
                // laid out using excess space. These views will get measured
                // later if we have space to distribute.
                final int totalLength = mTotalLength;
                mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
                skippedMeasure = true;
            } else {
                if (useExcessSpace) {
                    // The heightMode is either UNSPECIFIED or AT_MOST, and
                    // this child is only laid out using excess space. Measure
                    // using WRAP_CONTENT so that we can find out the view's
                    // optimal height. We'll restore the original height of 0
                    // after measurement.
                    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).
                final int usedHeight = totalWeight == 0 ? mTotalLength : 0;
                measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
                        heightMeasureSpec, usedHeight);

                final int childHeight = child.getMeasuredHeight();
                if (useExcessSpace) {
                    // Restore the original height and record how much space
                    // we've allocated to excess-only children so that we can
                    // match the behavior of EXACTLY measurement.
                    lp.height = 0;
                    consumedExcessSpace += childHeight;
                }

                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);
        }

        if (mTotalLength > 0 && hasDividerBeforeChildAt(count)) {
            mTotalLength += mDividerHeight;
        }

        if (useLargestChild &&
                (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {
            mTotalLength = 0;

            for (int i = 0; i < count; ++i) {
                final View child = getVirtualChildAt(i);
                if (child == null) {
                    mTotalLength += measureNullChild(i);
                    continue;
                }

                if (child.getVisibility() == GONE) {
                    i += getChildrenSkipCount(child, i);
                    continue;
                }

                final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
                        child.getLayoutParams();
                // Account for negative margins
                final int totalLength = mTotalLength;
                mTotalLength = Math.max(totalLength, totalLength + largestChildHeight +
                        lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
            }
        }

        // Add in our padding
        mTotalLength += mPaddingTop + mPaddingBottom;

        int heightSize = mTotalLength;

        // Check against our minimum height
        heightSize = Math.max(heightSize, getSuggestedMinimumHeight());

        // Reconcile our calculated size with the heightMeasureSpec
        int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);
        heightSize = heightSizeAndState & MEASURED_SIZE_MASK;

        // Either expand children with weight to take up available space or
        // shrink them if they extend beyond our current bounds. If we skipped
        // measurement on any children, we need to measure them now.
        int remainingExcess = heightSize - mTotalLength
                + (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace);
        if (skippedMeasure || remainingExcess != 0 && totalWeight > 0.0f) {
            float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;

            mTotalLength = 0;

            for (int i = 0; i < count; ++i) {
                final View child = getVirtualChildAt(i);
                if (child == null || child.getVisibility() == View.GONE) {
                    continue;
                }

                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                final float childWeight = lp.weight;
                if (childWeight > 0) {
                    final int share = (int) (childWeight * remainingExcess / remainingWeightSum);
                    remainingExcess -= share;
                    remainingWeightSum -= childWeight;

                    final int childHeight;
                    if (mUseLargestChild && heightMode != MeasureSpec.EXACTLY) {
                        childHeight = largestChildHeight;
                    } else if (lp.height == 0 && (!mAllowInconsistentMeasurement
                            || heightMode == MeasureSpec.EXACTLY)) {
                        // This child needs to be laid out from scratch using
                        // only its share of excess space.
                        childHeight = share;
                    } else {
                        // This child had some intrinsic height to which we
                        // need to add its share of excess space.
                        childHeight = child.getMeasuredHeight() + share;
                    }

                    final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
                            Math.max(0, childHeight), MeasureSpec.EXACTLY);
                    final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
                            mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
                            lp.width);
                    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);

                    // Child may now not fit in vertical dimension.
                    childState = combineMeasuredStates(childState, child.getMeasuredState()
                            & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));
                }

                final int margin =  lp.leftMargin + lp.rightMargin;
                final int measuredWidth = child.getMeasuredWidth() + margin;
                maxWidth = Math.max(maxWidth, measuredWidth);

                boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY &&
                        lp.width == LayoutParams.MATCH_PARENT;

                alternativeMaxWidth = Math.max(alternativeMaxWidth,
                        matchWidthLocally ? margin : measuredWidth);

                allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;

                final int totalLength = mTotalLength;
                mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredHeight() +
                        lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
            }

            // Add in our padding
            mTotalLength += mPaddingTop + mPaddingBottom;
            // TODO: Should we recompute the heightSpec based on the new total length?
        } else {
            alternativeMaxWidth = Math.max(alternativeMaxWidth,
                                           weightedMaxWidth);


            // We have no limit, so make all weighted views as tall as the largest child.
            // Children will have already been measured once.
            if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {
                for (int i = 0; i < count; i++) {
                    final View child = getVirtualChildAt(i);
                    if (child == null || child.getVisibility() == View.GONE) {
                        continue;
                    }

                    final LinearLayout.LayoutParams lp =
                            (LinearLayout.LayoutParams) child.getLayoutParams();

                    float childExtra = lp.weight;
                    if (childExtra > 0) {
                        child.measure(
                                MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),
                                        MeasureSpec.EXACTLY),
                                MeasureSpec.makeMeasureSpec(largestChildHeight,
                                        MeasureSpec.EXACTLY));
                    }
                }
            }
        }

        if (!allFillParent && widthMode != MeasureSpec.EXACTLY) {
            maxWidth = alternativeMaxWidth;
        }

        maxWidth += mPaddingLeft + mPaddingRight;

        // Check against our minimum width
        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());

        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
                heightSizeAndState);

        if (matchWidth) {
            forceUniformWidth(count, heightMeasureSpec);
        }
    }

上面code的主要功能如下:
1、判断每一个subchild之前是否有divider
2、计算每一个subchild的宽和高
3、如果subchild设置了weight,根据weight来计算subchild的高
4、是否使用useLargestChild,是的话则找出subchild中height最大的一个value,然后设置每一个subchild的height都为这个value
5、测量linearLayout本身的宽和高

下面我们一点一点的分析measureVertical方法里面的code

        mTotalLength = 0;
        int maxWidth = 0;
        int childState = 0;
        int alternativeMaxWidth = 0;
        int weightedMaxWidth = 0;
        boolean allFillParent = true;
        float totalWeight = 0;

        final int count = getVirtualChildCount();

        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        boolean matchWidth = false;
        boolean skippedMeasure = false;

        final int baselineChildIndex = mBaselineAlignedChildIndex;        
        final boolean useLargestChild = mUseLargestChild;

        int largestChildHeight = Integer.MIN_VALUE;
        int consumedExcessSpace = 0;

这里主要是一些初始化的变量,在后面使用的时候我们再来具体讲解其作用

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;
    }

    final LayoutParams lp = (LayoutParams) child.getLayoutParams();

    totalWeight += lp.weight;

    final boolean useExcessSpace = lp.height == 0 && lp.weight > 0;
    if (heightMode == MeasureSpec.EXACTLY && useExcessSpace) {
        // Optimization: don't bother measuring children who are only
        // laid out using excess space. These views will get measured
        // later if we have space to distribute.
        final int totalLength = mTotalLength;
        mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
        skippedMeasure = true;
    } else {
        if (useExcessSpace) {
            // The heightMode is either UNSPECIFIED or AT_MOST, and
            // this child is only laid out using excess space. Measure
            // using WRAP_CONTENT so that we can find out the view's
            // optimal height. We'll restore the original height of 0
            // after measurement.
            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).
        final int usedHeight = totalWeight == 0 ? mTotalLength : 0;
        measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
                heightMeasureSpec, usedHeight);

        final int childHeight = child.getMeasuredHeight();
        if (useExcessSpace) {
            // Restore the original height and record how much space
            // we've allocated to excess-only children so that we can
            // match the behavior of EXACTLY measurement.
            lp.height = 0;
            consumedExcessSpace += childHeight;
        }

        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);
}

1、13~15行是判断subchild之前是否有divider,如果有的话,计算divider的高度,divider可以通过设置android:divider属性
这里写图片描述
2、21~29行判断subchild当height为0并且有设置weight大小时,用useExcessSpace来表示true/false,可理解为 是否要使用LinearLayout余下的空间,当linearLayout大小确定时,我们选择跳过该subchild的测量,等到后面通过weight来计算subchild的大小;当linearLayout大小不确定时,30~37的lp.height = LayoutParams.WRAP_CONTENT这样做是为了后面紧接着的测量用的,测量该subchild的内容应该的大小
3、44行的measureChildBeforeLayout方法是测量subchild大小的
4、48~54行,当subchild被测量并且有设置weight大小,此时用consumedExcessSpace 来保存所有这样的subchild的高的总和
5、60~62行找出所有subchild里面height的value最大的
6、83~110这之间主要是为了找出subchild中width最大的value,以给最后的LinearLayout自己测量用的

if (useLargestChild &&
        (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {
    mTotalLength = 0;

    for (int i = 0; i < count; ++i) {
        final View child = getVirtualChildAt(i);
        if (child == null) {
            mTotalLength += measureNullChild(i);
            continue;
        }

        if (child.getVisibility() == GONE) {
            i += getChildrenSkipCount(child, i);
            continue;
        }

        final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
                child.getLayoutParams();
        // Account for negative margins
        final int totalLength = mTotalLength;
        mTotalLength = Math.max(totalLength, totalLength + largestChildHeight +
                lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
    }
}
假如1~2行的条件满足的话,直接看组后21~22行,此时LinearLayout会把每一个subchild的height都当成是largestChildHeight 来统计
// Add in our padding
mTotalLength += mPaddingTop + mPaddingBottom;

int heightSize = mTotalLength;

// Check against our minimum height
heightSize = Math.max(heightSize, getSuggestedMinimumHeight());

// Reconcile our calculated size with the heightMeasureSpec
int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);
heightSize = heightSizeAndState & MEASURED_SIZE_MASK;

// Either expand children with weight to take up available space or
// shrink them if they extend beyond our current bounds. If we skipped
// measurement on any children, we need to measure them now.
int remainingExcess = heightSize - mTotalLength
        + (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace);
 上面几行是计算LinearLayout的height大小的,最后16~17行计算所有subchild之外,LinearLayout剩余的未使用的垂直方向的空间大小。
if (skippedMeasure || remainingExcess != 0 && totalWeight > 0.0f) {
    float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;

    mTotalLength = 0;

    for (int i = 0; i < count; ++i) {
        final View child = getVirtualChildAt(i);
        if (child == null || child.getVisibility() == View.GONE) {
            continue;
        }

        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
        final float childWeight = lp.weight;
        if (childWeight > 0) {
            final int share = (int) (childWeight * remainingExcess / remainingWeightSum);
            remainingExcess -= share;
            remainingWeightSum -= childWeight;

            final int childHeight;
            if (mUseLargestChild && heightMode != MeasureSpec.EXACTLY) {
                childHeight = largestChildHeight;
            } else if (lp.height == 0 && (!mAllowInconsistentMeasurement
                    || heightMode == MeasureSpec.EXACTLY)) {
                // This child needs to be laid out from scratch using
                // only its share of excess space.
                childHeight = share;
            } else {
                // This child had some intrinsic height to which we
                // need to add its share of excess space.
                childHeight = child.getMeasuredHeight() + share;
            }

            final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
                    Math.max(0, childHeight), MeasureSpec.EXACTLY);
            final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
                    mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
                    lp.width);
            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);

            // Child may now not fit in vertical dimension.
            childState = combineMeasuredStates(childState, child.getMeasuredState()
                    & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));
        }

        final int margin =  lp.leftMargin + lp.rightMargin;
        final int measuredWidth = child.getMeasuredWidth() + margin;
        maxWidth = Math.max(maxWidth, measuredWidth);

        boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY &&
                lp.width == LayoutParams.MATCH_PARENT;

        alternativeMaxWidth = Math.max(alternativeMaxWidth,
                matchWidthLocally ? margin : measuredWidth);

        allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;

        final int totalLength = mTotalLength;
        mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredHeight() +
                lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
    }

    // Add in our padding
    mTotalLength += mPaddingTop + mPaddingBottom;
    // TODO: Should we recompute the heightSpec based on the new total length?
} else {

1、上面的if-else满足的添加是之前有subchild有跳过测量,或者是有sunchild设置了weight的值并且LinearLayout垂直方向的空间没有被使用完。
2、这里需要注意的是,假如一共有3个subchild且都有设置weight ,分别为3、2、1,我们假设剩余的space为120,则第一个view的大小为120 * 3/(3+2+1)=60,第二个view的大小为(120-60)*2/(2+1)=40,第3个view的大小为(60-40)*1/1 = 20
3、上面其余的code就不多解释了,通过前面code的分析这里因该可以看的明白

else {
    alternativeMaxWidth = Math.max(alternativeMaxWidth,
                                   weightedMaxWidth);


    // We have no limit, so make all weighted views as tall as the largest child.
    // Children will have already been measured once.
    if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {
        for (int i = 0; i < count; i++) {
            final View child = getVirtualChildAt(i);
            if (child == null || child.getVisibility() == View.GONE) {
                continue;
            }

            final LinearLayout.LayoutParams lp =
                    (LinearLayout.LayoutParams) child.getLayoutParams();

            float childExtra = lp.weight;
            if (childExtra > 0) {
                child.measure(
                        MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),
                                MeasureSpec.EXACTLY),
                        MeasureSpec.makeMeasureSpec(largestChildHeight,
                                MeasureSpec.EXACTLY));
            }
        }
    }
}

这一段code就不分析了,都很简单

setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
        heightSizeAndState);

if (matchWidth) {
    forceUniformWidth(count, heightMeasureSpec);
}

最后,设置LinearLayout的size大小和状态,如果LinearLayout有设置width为match_parent的话,将会调用forceUniformWidth再测量一次所有的subchild,这里主要是测量subchild的width大小

下面我们继续分析LayoutVertical方法

void layoutVertical(int left, int top, int right, int bottom) {
        final int paddingLeft = mPaddingLeft;

        int childTop;
        int childLeft;

        // Where right end of child should go
        final int width = right - left;
        int childRight = width - mPaddingRight;

        // Space available for child
        int childSpace = width - paddingLeft - mPaddingRight;

        final int count = getVirtualChildCount();

        final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
        final int minorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;

        switch (majorGravity) {
           case Gravity.BOTTOM:
               // mTotalLength contains the padding already
               childTop = mPaddingTop + bottom - top - mTotalLength;
               break;

               // mTotalLength contains the padding already
           case Gravity.CENTER_VERTICAL:
               childTop = mPaddingTop + (bottom - top - mTotalLength) / 2;
               break;

           case Gravity.TOP:
           default:
               childTop = mPaddingTop;
               break;
        }

        for (int i = 0; i < count; i++) {
            final View child = getVirtualChildAt(i);
            if (child == null) {
                childTop += measureNullChild(i);
            } else if (child.getVisibility() != GONE) {
                final int childWidth = child.getMeasuredWidth();
                final int childHeight = child.getMeasuredHeight();

                final LinearLayout.LayoutParams lp =
                        (LinearLayout.LayoutParams) child.getLayoutParams();

                int gravity = lp.gravity;
                if (gravity < 0) {
                    gravity = minorGravity;
                }
                final int layoutDirection = getLayoutDirection();
                final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
                switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
                    case Gravity.CENTER_HORIZONTAL:
                        childLeft = paddingLeft + ((childSpace - childWidth) / 2)
                                + lp.leftMargin - lp.rightMargin;
                        break;

                    case Gravity.RIGHT:
                        childLeft = childRight - childWidth - lp.rightMargin;
                        break;

                    case Gravity.LEFT:
                    default:
                        childLeft = paddingLeft + lp.leftMargin;
                        break;
                }

                if (hasDividerBeforeChildAt(i)) {
                    childTop += mDividerHeight;
                }

                childTop += lp.topMargin;
                setChildFrame(child, childLeft, childTop + getLocationOffset(child),
                        childWidth, childHeight);
                childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);

                i += getChildrenSkipCount(child, i);
            }
        }
    }

上面的code的大体功能如下:
1、LinearLayout里面所有的subChild作为一个整体,判断是处于LinearLayout的top、bottom还是center_vertical
2、循环遍历subChild来设置child在LinearLayout中的位置,code很简单,细心看很容易明白
3、setChildFrame方法最终是调用了child.layout 方法

ok,关于LienarLayout方面的分析到此结束!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值