What determines the MeasureSpec of a View during measurement ?, Viewmeasurespec

Source: Internet
Author: User

What determines the MeasureSpec of a View during measurement ?, Viewmeasurespec

 

We all know that to determine the View size, the system must first obtain MeasureSpec and then determine the View size through MeasureSpec.

MeasureSpec (32 is an int value) consists of two parts:

SpecMode (2-bit high): Measurement Mode.

SpecSize (30-bit lower): The specification size in a certain measurement mode.

 

SpecMode has three types:

UNSPECIFIED:The parent container does not limit the size of the view. It is generally used inside the system to indicate a measurement state.

EXACTLY:Exact mode. It corresponds to match_parent and a specific value in LayoutPrams.

AT_MOST:Maximum mode. Corresponds to the wrap_content mode in LayoutParam.

 

So the question is, what determines this MeasureSpec? Let's start with the source code.

The ViewGroup contains a method called measureChildWithMargins, which is used to measure the size of a subview.

/**     * Ask one of the children of this view to measure itself, taking into     * account both the MeasureSpec requirements for this view and its padding     * and margins. The child must have MarginLayoutParams The heavy lifting is     * done in getChildMeasureSpec.     *     * @param child The child to measure     * @param parentWidthMeasureSpec The width requirements for this view     * @param widthUsed Extra space that has been used up by the parent     *        horizontally (possibly by other children of the parent)     * @param parentHeightMeasureSpec The height requirements for this view     * @param heightUsed Extra space that has been used up by the parent     *        vertically (possibly by other children of the parent)     */    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);    }

It can be seen that in the code, childWidthMeasureSpec and childHeightMeasureSpec are obtained first, and then child. measure (childWidthMeasureSpec, childHeightMeasureSpec) is measured );

The key is to see how the two MeasureSpec are obtained. getChildMeasureSpec (parentWidthMeasureSpec,
MPaddingLeft + mPaddingRight + lp. leftMargin + lp. rightMargin
+ WidthUsed, lp. width); we can see thatObtaining MeasureSpec is not only related to the LayoutParam of the child element, but also to the MeasureSpec of the parent container. Of course, it is also related to its padding and margin.
Let's take a look. This part of the code is a bit long, but the logic in it is very simple. We directly add comments to the source code for analysis.

/*** Does the hard part of measureChildren: figuring out the MeasureSpec to * pass to a participant child. this method figures out the right MeasureSpec * for one dimension (height or width) of one child view. ** The goal is to combine information from our MeasureSpec with the * LayoutParams of the child to get the best possible results. for example, * if the this view knows its size (because its MeasureSpec has a mode of * EXACTLY ), and the child has indicated in its LayoutParams that it wants * to be the same size as the parent, the parent shocould ask the child to * layout given an exact size. ** @ param spec The requirements for this view * @ param padding The padding of this view for the current dimension and * margins, if applicable * @ param childDimension How big the child wants to be in the current * dimension * @ return a MeasureSpec integer for the child */public static int getChildMeasureSpec (int spec, int padding, int childDimension) {int specMode = MeasureSpec. getMode (spec); // obtain the Measurement Mode of the parent container. int specSize = MeasureSpec. getSize (spec); // obtain the size of the parent container in this measurement mode. int size = Math. max (0, specSize-padding); int resultSize = 0; // specSize int resultMode of the child element = 0; // specMode switch (specMode) of the child element) {// Parent has imposed an exact size on us case MeasureSpec. EXACTLY: // if the Measurement Mode of the parent container is EXACTLY if (childDimension> = 0) {// if the LayoutParam of the child element is a specific value> = 0 resultSize = childDimension; // The specSize of the child element is childDimension resultMode = MeasureSpec. EXACTLY; // The specMode of the child element is EXACTLY.
// The following analyses are the same, so you will not write} 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: 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 shocould // be
// Here, View. sUseZeroUnspecifiedMeasureSpec is always false, so resultSize = 0; 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 shocould be resultSize = View. sUseZeroUnspecifiedMeasureSpec? 0: size; resultMode = MeasureSpec. UNSPECIFIED;} break;} return MeasureSpec. makeMeasureSpec (resultSize, resultMode );}


From the above analysis, we can see the sub-element'sObtaining MeasureSpec is not only related to the LayoutParam of the child element, but also to the MeasureSpec of the parent container. Of course, it is also related to its padding and margin.

In fact, we can draw the following conclusion:

 

 

ParentMeasureSpec

 

ChildLayoutParam

EXACTLY

AT_MOST

UNSPECIFIED

Specific Value

EXACTLLY

ChildSize

EXACTLY

ChildSize

EXACTLY

ChildSize

Match_parent

EXACTLY

ParentSize

AT_MOST

ParentSize

UNSPECIFIED

0

Wrap_content

AT_MOST

ParentSize

AT_MOST

ParentSize

UNSPECIFIED

0

ParentSize is the remaining space of the parent container.

As shown in the preceding table, when we inherit view to implement custom controls, we need to override the onMeasure method and set the size of wrap_content, otherwise, the use of wrap_content is equivalent to the use of match_parent. We can use the following template:

@Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int widthSpecMode=MeasureSpec.getMode(widthMeasureSpec);        int heightSpecMode=MeasureSpec.getMode(heightMeasureSpec);        int widthSpecSize=MeasureSpec.getSize(widthMeasureSpec);        int heightSpecSize=MeasureSpec.getSize(heightMeasureSpec);        if (widthSpecMode==MeasureSpec.AT_MOST && heightSpecMode==MeasureSpec.AT_MOST)        {            setMeasuredDimension(100,100);        }        else if (widthSpecMode==MeasureSpec.AT_MOST)        {            setMeasuredDimension(100,heightSpecSize);        }        else if (heightSpecMode==MeasureSpec.AT_MOST)        {            setMeasuredDimension(widthSpecSize,100);        }    }

In the above Code, 100 is the value we set. You can also use other values as needed.

 

The above is the analysis of the MeasureSpec.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.