measure過(guò)程

view的大三流程開(kāi)始之地在performTraversals過(guò)程中栅受,而measure是三個(gè)流程中較為復(fù)雜的過(guò)程侵佃。而measure的開(kāi)始地方在performTraversals中的代碼片段:

            .....
            //mStopped==true,該窗口activity處于停止?fàn)顟B(tài)
            //mReportNextDraw,Window上報(bào)下一次繪制
            if (!mStopped || mReportNextDraw) {
                //觸摸模式發(fā)生了變化,且檢測(cè)焦點(diǎn)的控件發(fā)生了變化
                boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
                        (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
                //1. 焦點(diǎn)控件發(fā)生變化
                //2. 窗口寬高測(cè)量值 檐春!= WMS計(jì)算的mWinFrame寬高
                //3. contentInsetsChanged==true顽聂,邊襯區(qū)域發(fā)生變化
                if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
                        || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
                        updatedConfiguration) {
                    int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
                    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);

                    //------開(kāi)始執(zhí)行測(cè)量操作--------
                     // Ask host how big it wants to be
                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
             .....

可見(jiàn)在measure流程開(kāi)始之前通過(guò)getRootMeasureSpec()獲取根布局的MeasureSpec并傳入performMeasure中開(kāi)始measure流程肥惭。

MeasureSpec

MeasureSpec代表一個(gè)32位int值,高2位為SpecMode紊搪,低30位為SpecSize蜜葱。在View中有MeasureSpec內(nèi)部類(lèi)定義對(duì)MeasureSpec的相關(guān)處理及常量定義。

        /** @hide */
        @IntDef({UNSPECIFIED, EXACTLY, AT_MOST})
        @Retention(RetentionPolicy.SOURCE)
        public @interface MeasureSpecMode {}

        /**
         * Measure specification mode: The parent has not imposed any constraint
         * on the child. It can be whatever size it wants.
         */
        public static final int UNSPECIFIED = 0 << MODE_SHIFT;

        /**
         * Measure specification mode: The parent has determined an exact size
         * for the child. The child is going to be given those bounds regardless
         * of how big it wants to be.
         */
        public static final int EXACTLY     = 1 << MODE_SHIFT;

        /**
         * Measure specification mode: The child can be as large as it wants up
         * to the specified size.
         */
        public static final int AT_MOST     = 2 << MODE_SHIFT;

        // Creates a measure specification based on the supplied size and mode.
        public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
                                          @MeasureSpecMode int mode) {
            if (sUseBrokenMakeMeasureSpec) {
                return size + mode;
            } else {
                return (size & ~MODE_MASK) | (mode & MODE_MASK);
            }
        }

SpecMode有三種情況:

  • UNSPECIFIED:父布局對(duì)View沒(méi)有任何約束耀石,View可以是任何它想要的尺寸牵囤。
  • EXACTLY:父布局精確設(shè)定了View的大小,無(wú)論子布局想要多大的都將得到父布局給予的精確邊界滞伟。這種情況實(shí)際上就對(duì)應(yīng)的是我們?cè)趚ml文件或者LayoutParams中設(shè)置的xxdp/px或者M(jìn)ATH_PARENT這兩種情況揭鳞,也就是精確的給予了布局邊界。
  • AT_MOST:在確定的尺寸(父布局指定的SpecSize)內(nèi)诗良,View可以盡可能的大但不得超出SpecSize大小汹桦。這種情況對(duì)應(yīng)的就是我們?cè)趚ml文件或者LayoutParams中設(shè)置的WRAP_CONTENT,子View可以隨著內(nèi)容的增加而申請(qǐng)更大的尺寸,但是不能超過(guò)指定的SpecSize鉴裹。

在measure過(guò)程中舞骆,對(duì)于除了DecorView外的View,其MeasureSpec由父容器的MeasureSpec和自身的LayoutParams共同決定的(還與View的margin和padding有關(guān))径荔;而對(duì)于DecorView來(lái)說(shuō)督禽,其MeasureSpec由它自身的LayoutParams決定。

DecorView的MeasureSpec

    private static int getRootMeasureSpec(int windowSize, int rootDimension) {
        int measureSpec;
        switch (rootDimension) {

        case ViewGroup.LayoutParams.MATCH_PARENT:
            // Window can't resize. Force root view to be windowSize.
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
            break;
        case ViewGroup.LayoutParams.WRAP_CONTENT:
            // Window can resize. Set max size for root view.
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
            break;
        default:
            // Window wants to be an exact size. Force root view to be that size.
            measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
            break;
        }
        return measureSpec;
    }

因?yàn)镈ectorView的MeasureSpec只與自身LayoutParams有關(guān)总处”繁梗可以分為三種情況:

  • LayoutParams.MATH_PARENT:MeasureSpec.EXACTLY模式,強(qiáng)制DectorView大小與window大小一致
  • LayoutParams.WRAP_CONTENT:MeasureSpec.AT_MOST模式,且不可超過(guò)window大小
  • default:MeasureSpec.EXACTLY模式胧谈,指定為DectorView的lp大小

View的MeasureSpec

View的mesure過(guò)程由ViewGroup傳遞忆肾。ViewGroup則相對(duì)復(fù)雜一些。

    protected void measureChildWithMargins(View child,
            int parentWidthMeasureSpec, int widthUsed,
            int parentHeightMeasureSpec, int heightUsed) {
        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
                        + widthUsed, lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
                        + heightUsed, lp.height);

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

這就與上文說(shuō)到的對(duì)于除了DecorView外的View菱肖,其MeasureSpec由父容器的MeasureSpec和自身的LayoutParams共同決定的(還與View的margin和padding有關(guān))客冈。
子View的MeasureSpec創(chuàng)建:與父容器的MeasureSpec自身的LayoutParams有關(guān),此外還和View的margin及padding有關(guān)稳强。

    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
        int specMode = MeasureSpec.getMode(spec);
        int specSize = MeasureSpec.getSize(spec);
        //子View可用空間
        int size = Math.max(0, specSize - padding);

        int resultSize = 0;
        int resultMode = 0;

        switch (specMode) {
        // Parent has imposed an exact size on us
        case MeasureSpec.EXACTLY:   //父布局為EXACTLY模式场仲,對(duì)應(yīng)match_parent及dp/px
            if (  >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size. So be it.
                resultSize = size;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent has imposed a maximum size on us
        case MeasureSpec.AT_MOST:   //父布局為AT_MOST模式,
            if (childDimension >= 0) {
                // Child wants a specific size... so be it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size, but our size is not fixed.
                // Constrain child to not be bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent asked to see how big we want to be
        case MeasureSpec.UNSPECIFIED:
            if (childDimension >= 0) {
                // Child wants a specific size... let him have it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size... find out how big it should
                // be
                resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                resultMode = MeasureSpec.UNSPECIFIED;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size.... find out how
                // big it should be
                resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                resultMode = MeasureSpec.UNSPECIFIED;
            }
            break;
        }
        //noinspection ResourceType
        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
    }

最終可以整理出一個(gè)表格退疫,引用《Android開(kāi)發(fā)藝術(shù)探索》中的表圖渠缕。


MeasureSpec

稍微整理則是:

  • 當(dāng)子view指定dp/px :使用EXACTLY模式,并遵循LayoutParams大小
  • 當(dāng)子view寬/高為match_parent :
    • 父布局為EXACTLY褒繁,則子view為EXACTLY亦鳞,且大小為parent可用大小
    • 父布局為AT_MOST,則子view為AT_MOST澜汤,且大小為parent可用大小
  • 當(dāng)子view寬/高為wrap_content:使用AT_MOST蚜迅,且大小為parent可用大小

而UNSPECIFIED一般我們?cè)陂_(kāi)發(fā)時(shí)不會(huì)用到故而不做分析。

measure

因?yàn)関iew通過(guò)measure即可完成測(cè)量過(guò)程俊抵,而ViewGroup還需要遍歷調(diào)用子view的measure方法谁不。所以需要分別討論。

View的measure

View的measure由measure方法完成徽诲,而measure方法為final類(lèi)型子類(lèi)不可重寫(xiě)刹帕。在measure方法中會(huì)調(diào)用onMeasure方法,且具體測(cè)量過(guò)程都是在該方法中完成谎替。

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }

    //1.AT_MOST偷溺、EXACTLY情況下返回MeasureSpec中的Size
    //2.UNSPECIFIED使用getSuggestedMinimumXX的返回值
    public static int getDefaultSize(int size, int measureSpec) {
        int result = size;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        switch (specMode) {
        case MeasureSpec.UNSPECIFIED:
            result = size;
            break;
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY:
            result = specSize;
            break;
        }
        return result;
    }

    //1.無(wú)背景:使用android:minWidth(mMinWidth)的值(可為0)
    //2.有背景:取背景大小或mMinWidth中的 最大值
    protected int getSuggestedMinimumWidth() {
        return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
    }
    protected int getSuggestedMinimumHeight() {
        return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());
    }

一般我們只會(huì)使用到AT_MOST、EXACTLY模式钱贯,但是需要注意的是當(dāng)為AT_MOST下默認(rèn)使用的是parentSize挫掏,即相當(dāng)于match_parent,所以自定義view要實(shí)現(xiàn)wrap_content時(shí)需要自己實(shí)現(xiàn)秩命。
而使用UNSPECIFIED尉共,則是

  • 有背景,取背景大小和mMinWidth/mMinHeight 中最大值
  • 無(wú)背景弃锐,取mMinWidth/mMinHeight
    這樣子就確定了view的測(cè)量值袄友,而view最終大小則由layout過(guò)程確定,一般情況兩者一致霹菊。

ViewGroup的measure

因?yàn)閂iewGroup除了完成自己的measure還需要遍歷子view的measure過(guò)程剧蚣。而ViewGroup是個(gè)抽象類(lèi),提供了measureChlidren的方法,而對(duì)應(yīng)onMeasure則需要對(duì)應(yīng)實(shí)現(xiàn)的ViewGroup子類(lèi)去實(shí)現(xiàn)了鸠按。

    protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
        final int size = mChildrenCount;
        final View[] children = mChildren;
        for (int i = 0; i < size; ++i) {
            final View child = children[i];
            if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
                measureChild(child, widthMeasureSpec, heightMeasureSpec);//對(duì)每個(gè)children進(jìn)行measure
            }
        }
    }
    protected void measureChild(View child, int parentWidthMeasureSpec,
            int parentHeightMeasureSpec) {
        final LayoutParams lp = child.getLayoutParams();
        //getChildMeasureSpec可看上文的MeasureSpec解析
        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                mPaddingLeft + mPaddingRight, lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                mPaddingTop + mPaddingBottom, lp.height);

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

看見(jiàn)measureChildren時(shí)對(duì)Visibility==GONE的view不進(jìn)行measure操作礼搁。對(duì)于不同ViewGroup得分析網(wǎng)上已經(jīng)有很多分析了。這里稍微總結(jié)一下就是目尖,

  • LinearLayout(vertical):先測(cè)量所有子View大小叹坦,根據(jù)子View總高度和自身MeasureSpec得出剩余空間去分配使用weiget的view的大小,最后測(cè)量自身大小卑雁。
  • RelativeLayout:根據(jù)依賴(lài)分別排序垂直和水平方向的view,并針對(duì)垂直和水平方向的view進(jìn)行measure(一次水平一次垂直)绪囱,最后測(cè)量自身大小
  • FrameLayout:測(cè)量子View测蹲,測(cè)量自身,如果自身為非精準(zhǔn)模式而子View為match_parent則這些子view需要再次測(cè)量鬼吵。

測(cè)量完是不一定能拿到View的對(duì)應(yīng)測(cè)量大小的扣甲,因?yàn)橄到y(tǒng)在某些情況下可能進(jìn)行多次測(cè)量測(cè)能確定寬高。所以自定義view時(shí)最好在onLayout去獲取測(cè)量大小齿椅。外部獲取view大小可以通過(guò):

  • Activity/View#onWindowFocusChanged:這時(shí)view已經(jīng)初始化完成琉挖,但該方法可能多次被調(diào)用(獲取/失去焦點(diǎn)都會(huì)被調(diào)用)
  • View#post:在Android Handler原理源碼淺析知道,當(dāng)執(zhí)行runnable時(shí)view已經(jīng)初始化完成(MainLooper已經(jīng)完成繪制去除了消息屏障)
  • ViewTreeObserver:通過(guò)OnGlobalLayoutListener接口回調(diào)onGlobalLayout時(shí)view樹(shù)可見(jiàn)性已經(jīng)發(fā)生變化涣脚,這時(shí)去獲取view的寬高則可以(這個(gè)接口可能多次調(diào)用示辈,回調(diào)后需取消監(jiān)聽(tīng))

LinearLayout Measure過(guò)程(Vertical)

void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {

        final int count = getVirtualChildCount();

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


        // See how tall everyone is. Also remember max width.
        for (int i = 0; i < count; ++i) {
            //null 或者 GONE 跳過(guò)measure
            ......

            totalWeight += lp.weight;

            final boolean useExcessSpace = lp.height == 0 && lp.weight > 0;
            if (heightMode == MeasureSpec.EXACTLY && useExcessSpace) {
                //精準(zhǔn)模式直接記錄children高度

                // 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;
                //measure子view高度
                measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
                        heightMeasureSpec, usedHeight);

                //記錄children高度
                .....
            }

            .....
        }

        ......

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

        int heightSize = mTotalLength;

        // Check against our minimum height
        heightSize = Math.max(heightSize, getSuggestedMinimumHeight());
        //測(cè)量自身高度,方便計(jì)算是否還是有剩余高度
        // 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);
        //當(dāng)有還有剩余空間遣蚀,則針對(duì)對(duì)應(yīng)weight分配空間
        .....

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

        maxWidth += mPaddingLeft + mPaddingRight;

        // Check against our minimum width
        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
        //設(shè)置自身測(cè)量大小
        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
                heightSizeAndState);

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

RelativeLayout onMeasure

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mDirtyHierarchy) {
            mDirtyHierarchy = false;
            sortChildren();//根據(jù)依賴(lài)圖分別按垂直和水平排序子view
        }

        ...
        //根據(jù)水平方向依賴(lài)關(guān)系矾麻,measure子view
        View[] views = mSortedHorizontalChildren;
        int count = views.length;

        for (int i = 0; i < count; i++) {
            View child = views[i];
            if (child.getVisibility() != GONE) {
                LayoutParams params = (LayoutParams) child.getLayoutParams();
                int[] rules = params.getRules(layoutDirection);

                applyHorizontalSizeRules(params, myWidth, rules);
                measureChildHorizontal(child, params, myWidth, myHeight);

                if (positionChildHorizontal(child, params, myWidth, isWrapContentWidth)) {
                    offsetHorizontalAxis = true;
                }
            }
        }
        //根據(jù)垂直方向依賴(lài)關(guān)系,measure子view
        views = mSortedVerticalChildren;
        count = views.length;
        final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;

        for (int i = 0; i < count; i++) {
            final View child = views[i];
            if (child.getVisibility() != GONE) {
                final LayoutParams params = (LayoutParams) child.getLayoutParams();

                applyVerticalSizeRules(params, myHeight, child.getBaseline());
                measureChild(child, params, myWidth, myHeight);
                if (positionChildVertical(child, params, myHeight, isWrapContentHeight)) {
                    offsetVerticalAxis = true;
                }

                ....
            }
        }

        //測(cè)量自身
        ....

        setMeasuredDimension(width, height);
    }

FrameLayout onMeasure

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int count = getChildCount();
        //是否需要測(cè)量match_parent的子view芭梯,當(dāng)為精準(zhǔn)模式不需要測(cè)量match_parent的子view
        final boolean measureMatchParentChildren =
                MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
                MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
        mMatchParentChildren.clear();

        int maxHeight = 0;
        int maxWidth = 0;
        int childState = 0;

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (mMeasureAllChildren || child.getVisibility() != GONE) {
                //測(cè)量ziview
                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                maxWidth = Math.max(maxWidth,
                        child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
                maxHeight = Math.max(maxHeight,
                        child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
                childState = combineMeasuredStates(childState, child.getMeasuredState());
                //將match_parent子view添加進(jìn)列表险耀,需要再次測(cè)量
                if (measureMatchParentChildren) {
                    if (lp.width == LayoutParams.MATCH_PARENT ||
                            lp.height == LayoutParams.MATCH_PARENT) {
                        mMatchParentChildren.add(child);
                    }
                }
            }
        }

        .....
        //測(cè)量自身大小
        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
                resolveSizeAndState(maxHeight, heightMeasureSpec,
                        childState << MEASURED_HEIGHT_STATE_SHIFT));

        count = mMatchParentChildren.size();
        //自身非精準(zhǔn)模式,而子view為match_parent需要重新測(cè)量這些view
        if (count > 1) {
            for (int i = 0; i < count; i++) {
                final View child = mMatchParentChildren.get(i);
                final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

                final int childWidthMeasureSpec;
                if (lp.width == LayoutParams.MATCH_PARENT) {
                    final int width = Math.max(0, getMeasuredWidth()
                            - getPaddingLeftWithForeground() - getPaddingRightWithForeground()
                            - lp.leftMargin - lp.rightMargin);
                    childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
                            width, MeasureSpec.EXACTLY);
                } else {
                    childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
                            getPaddingLeftWithForeground() + getPaddingRightWithForeground() +
                            lp.leftMargin + lp.rightMargin,
                            lp.width);
                }

                final int childHeightMeasureSpec;
                if (lp.height == LayoutParams.MATCH_PARENT) {
                    final int height = Math.max(0, getMeasuredHeight()
                            - getPaddingTopWithForeground() - getPaddingBottomWithForeground()
                            - lp.topMargin - lp.bottomMargin);
                    childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
                            height, MeasureSpec.EXACTLY);
                } else {
                    childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
                            getPaddingTopWithForeground() + getPaddingBottomWithForeground() +
                            lp.topMargin + lp.bottomMargin,
                            lp.height);
                }

                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
            }
        }
    }

關(guān)于ConstraintLayout的measure解析玖喘,日后補(bǔ)上

參考:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末甩牺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子累奈,更是在濱河造成了極大的恐慌贬派,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件费尽,死亡現(xiàn)場(chǎng)離奇詭異赠群,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)旱幼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)查描,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事冬三≡扔停” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵勾笆,是天一觀(guān)的道長(zhǎng)敌蚜。 經(jīng)常有香客問(wèn)我,道長(zhǎng)窝爪,這世上最難降的妖魔是什么弛车? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蒲每,結(jié)果婚禮上纷跛,老公的妹妹穿的比我還像新娘。我一直安慰自己邀杏,他們只是感情好贫奠,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著望蜡,像睡著了一般唤崭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上脖律,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天谢肾,我揣著相機(jī)與錄音,去河邊找鬼状您。 笑死勒叠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的膏孟。 我是一名探鬼主播眯分,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼柒桑!你這毒婦竟也來(lái)了弊决?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后居凶,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡昆稿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了息拜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片溉潭。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡净响,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出喳瓣,到底是詐尸還是另有隱情馋贤,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布畏陕,位于F島的核電站配乓,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏惠毁。R本人自食惡果不足惜犹芹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鞠绰。 院中可真熱鬧羽莺,春花似錦、人聲如沸洞豁。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)丈挟。三九已至,卻和暖如春志电,著一層夾襖步出監(jiān)牢的瞬間曙咽,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工挑辆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留例朱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓鱼蝉,卻偏偏與公主長(zhǎng)得像洒嗤,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子魁亦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容