A. The opening

LinearLayout is easy to use, there is no rewrite of event distribution itself, the design of layout_weight is a highlight of the place, understanding how the interior works for your own custom View will also be a lot of help.

When the height is set to match_parent, and when the height is set to 0, the reverse is true. The first image is match, the second is 0dp, and of course the wrap is also different.

Height set to 0 when the source code parsing

There are two cases of horizontal and vertical LinearLayout. The vertical case is analyzed here, and the drawing process of View is also focused on onMeasure. In other cases, it is relatively simple, and height==0 is analyzed. Look at the code

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mOrientation == VERTICAL) {
            measureVertical(widthMeasureSpec, heightMeasureSpec);
        } else{ measureHorizontal(widthMeasureSpec, heightMeasureSpec); }}Copy the code

The mOrientation is set in the XML, so let’s look at some local variables first

 void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
        mTotalLength = 0; // The sum of the heights of the subviews does not equal the height of the LinearLayout
        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;

        int nonSkippedChildCount = 0; . }Copy the code

Now, how do we assign these variables, in three cycles

2.1 The first loop

        // See how tall everyone is. Also remember max width.
        for (int i = 0; i < count; ++i) {
            final View child = getVirtualChildAt(i);
            if (child == null) {
                // Count height as 0 if child is null
                mTotalLength += measureNullChild(i);
                continue;
            }

            if (child.getVisibility() == View.GONE) {
               // Skip if child is not displayed
               i += getChildrenSkipCount(child, i);
               continue;
            }

            nonSkippedChildCount++;
            if (hasDividerBeforeChildAt(i)) {
                // Calculate the height of the dividing line
                mTotalLength += mDividerHeight;
            }

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

            totalWeight += lp.weight;
            // Height is 0 and weight is greater than 0
            final boolean useExcessSpace = lp.height == 0 && lp.weight > 0;
            if (heightMode == MeasureSpec.EXACTLY && useExcessSpace) {
                // useExcessSpace is true
                mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
                skippedMeasure = true;
            } else {
                if (useExcessSpace) {
                    lp.height = LayoutParams.WRAP_CONTENT;
                }
                  // If the View before the View has weight, usedHeight is 0.Otherwise, it is the total height of the entire sub-componentfinal int usedHeight = totalWeight == 0 ? mTotalLength : 0;
                measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
                        heightMeasureSpec, usedHeight);

                final int childHeight = child.getMeasuredHeight();
                if (useExcessSpace) {
                    // height == 0
                    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); }}Copy the code

The above procedure shows that the child View height is too high when there is weight, of course this is only the first loop.

2.2 Second loop

// The condition for this loop is that useLargestChild is true
if (useLargestChild &&
                (widthMode == MeasureSpec.AT_MOST || widthMode == 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();
                if (isExactly) {
                    mTotalLength += largestChildWidth + lp.leftMargin + lp.rightMargin +
                            getNextLocationOffset(child);
                } else {
                    final inttotalLength = mTotalLength; mTotalLength = Math.max(totalLength, totalLength + largestChildWidth + lp.leftMargin + lp.rightMargin + getNextLocationOffset(child)); }}}Copy the code

2.3 The third cycle


            for (int i = 0; i < count; ++i) {
                ...
                 // mTotalLength == 0
                 int heightSize = mTotalLength;
                 The need to set up / / getSuggestedMinimumHeight default to 0 It is commonly heightSize
                 heightSize = Math.max(heightSize, getSuggestedMinimumHeight());
                 // resolveSizeAndState is the parent component height and 0, and heightSize is unchanged
                 int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);
                  // MEASURED_SIZE_MASK== 0x00FFFFFF,heightSize and the value and operation, because the height is not large enough, the result must be the same
                 heightSize = heightSizeAndState & MEASURED_SIZE_MASK;
                 int remainingExcess = heightSize - mTotalLength
                   + (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace);
                  if (childWeight > 0) {
                    // remainingExcess is the remaining space for assigning weight controls
                    final int share = (int) (childWeight * remainingExcess / remainingWeightSum);
                    remainingExcess -= share;
                    remainingWeightSum -= childWeight;

                    final int childHeight;
                    // Odp height is assigned by weight to height
                    if(mUseLargestChild && heightMode ! = MeasureSpec.EXACTLY) { childHeight = largestChildHeight; }else if (lp.height == 0&& (! mAllowInconsistentMeasurement || heightMode == MeasureSpec.EXACTLY)) { childHeight = share; }else {
                        // share can be negative
                        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)); }... }Copy the code

Height == match_parent

Just list the differences here

3.1 The first loop

TotalHeight = 2* Height of the parent component

3.2 Second loop

The same

3.3 The third loop

RemainingExcess = – Height of the parent component

Height == wrap_content

Just list the differences here

4.1 The first cycle

TotalHeight is approximately 2* the height of the text

4.2 Second cycle

The same

4.3 The third cycle

RemainingExcess = Height of parent component -2* height of text

Conclusion:

Height = (height of parent component – total height of child component) *weight/weightSum + original height of single child component

2. If there is a weight, the measure of the child view will be executed twice