自定义View测量模式解析

自定义View测量模式解析

自定义View的三种测量模式

1 MeasureSpec.EXACTLY

2 MeasureSpec.AT_MOST

3 MeasureSpec.UNSPECIFIED (用的很少 一般指ScrollView之类的控件)

以下是ViewGroup测量子View的代码

 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);
    }
参数childDimension即为child的布局参数MarginLayoutParams所决定的宽 lp.width 或 高 lp.height
 public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
          得到父布局自身的测量模式和测量宽或高 
        int specMode = MeasureSpec.getMode(spec);
        int specSize = MeasureSpec.getSize(spec);

        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:        
        // 当父布局自身的宽或高为 100dp 或 match_parent时 
            if (childDimension >= 0) {     子View测量宽或高大于0 
                resultSize = childDimension;   
                resultMode = MeasureSpec.EXACTLY;    子View测量的测量模式为MeasureSpec.EXACTLY
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
               子View希望测量宽或高是最大的  Child wants to be our size. So be it.
                // Child wants to be our size. So be it.

                resultSize = size;
                resultMode = MeasureSpec.EXACTLY;  子View测量的测量模式为MeasureSpec.EXACTLY
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
           // 子View希望测量宽或高只是自身的宽高,但是不能超过父View的宽或高,

                // 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:
        // 当父布局自身的宽或高为WRAP_CONTENT时 
            if (childDimension >= 0) {    
                //子View测量宽或高大于0
                // Child wants a specific size... so be it
                resultSize = childDimension;
                //子View测量的测量模式为MeasureSpec.EXACTLY
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
             //子View希望测量宽或高是最大的  但是最大也不能超过父View
                // Child wants to be our size, but our size is not fixed.
                // Constrain child to not be bigger than us.
                resultSize = size;
               // 子View测量的测量模式为MeasureSpec.AT_MOST
                resultMode = MeasureSpec.AT_MOST;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
            //子View希望测量宽或高只是自身的宽高  但是最大也不能超过父View
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                 // 子View测量的测量模式为MeasureSpec.AT_MOST
                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);
    }

模式和大小是由父布局和自己决定的

比方父布局是WRAP_CONTENT  就算子布局是match_parent,这个时候计算的测量模式还是 AT_MOST

比方父布局是match_parent  子布局是match_parent,这个时候计算的测量模式还是 EXACTLY

你可能感兴趣的:(自定义View)