Four. Customize View MeasureSpec

MeasureSpec

1. When customizing View, when onMeasure, MeasureSpec will be used. MeasureSpec is commonly called measurement specification.

2. The final width and height of an ordinary View are determined by the MeasurePec of the parent View and the LayoutParas of the child View.
3. The final width and height of the top-level View (DecorView) is determined by the size of the screen and its own LayoutParams.

3. MeasureSpec is a static internal class of View, MeasureSpec represents a 32-bit int value, the upper 2 bits represent SpecMode, the lower 30 bits represent SpecSize, SpecMode is the measurement mode , and SpecSiz is the measurement specification size

definition

Insert picture description here

There are three types of SpecMode as follows:

  • The UNSPECIFIED
    parent control does not impose any restrictions on you. Give you as much as you want. If you want to go to heaven, go to heaven. This situation is generally used inside the system to indicate a measurement state. (This mode is mainly used in the case of multiple measurements within the system. It does not really mean that you want to be as big as you want in the end.)
  • The EXACTLY
    parent control already knows the exact size you need , and your final size should be this large. It corresponds to match_parent and specific value in LayoutParams .
  • AT_MOST
    your size cannot be larger than the size specified by the parent control, but the specific size depends on your own implementation. It corresponds to wrap_content in LayoutParams

MeasureSpec meaning:

By packing SpecMode and SpecSize into an int value, excessive object memory allocation can be avoided. In order to facilitate operation, it provides packing/unpacking methods

Determination of MeasureSpec value

Insert picture description hereThe MeasureSpec value of the child View is calculated based on the layout parameters (LayoutParams) of the child View and the MeasureSpec value of the parent container. The specific
calculation logic is encapsulated in getChildMeasureSpec ()

 /**
     *
     * 目标是将父控件的测量规格 和 child view的布局参数LayoutParams相结合,得到一个
     * 最可能符合条件的child view的测量规格。  

     * @param spec 父控件的测量规格
     * @param padding 父控件里已经占用的大小
     * @param childDimension child view布局LayoutParams里的尺寸
     * @return child view 的测量规格
     */
    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) {
    
    
        // 当父控件的测量模式 是 精确模式,也就是有精确的尺寸了
        case MeasureSpec.EXACTLY:
            //如果child的布局参数有固定值,比如"layout_width" = "100dp"
            //那么显然child的测量规格也可以确定下来了,测量大小就是100dp,测量模式也是EXACTLY
            if (childDimension >= 0) {
    
    
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } 

            //如果child的布局参数是"match_parent",也就是想要占满父控件
            //而此时父控件是精确模式,也就是能确定自己的尺寸了,那child也能确定自己大小了
            else if (childDimension == LayoutParams.MATCH_PARENT) {
    
    
                resultSize = size;
                resultMode = MeasureSpec.EXACTLY;
            }
            //如果child的布局参数是"wrap_content",也就是想要根据自己的逻辑决定自己大小,
            //比如TextView根据设置的字符串大小来决定自己的大小
            //那就自己决定呗,不过你的大小肯定不能大于父控件的大小嘛
            //所以测量模式就是AT_MOST,测量大小就是父控件的size
            else if (childDimension == LayoutParams.WRAP_CONTENT) {
    
    
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // 当父控件的测量模式 是 最大模式,也就是说父控件自己还不知道自己的尺寸,但是大小不能超过size
        case MeasureSpec.AT_MOST:
            //同样的,既然child能确定自己大小,尽管父控件自己还不知道自己大小,也优先满足孩子的需求
            if (childDimension >= 0) {
    
    
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } 
            //child想要和父控件一样大,但父控件自己也不确定自己大小,所以child也无法确定自己大小
            //但同样的,child的尺寸上限也是父控件的尺寸上限size
            else if (childDimension == LayoutParams.MATCH_PARENT) {
    
    
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            //child想要根据自己逻辑决定大小,那就自己决定呗
            else if (childDimension == LayoutParams.WRAP_CONTENT) {
    
    
                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 = 0;
                resultMode = MeasureSpec.UNSPECIFIED;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
    
    
                // Child wants to determine its own size.... find out how
                // big it should be
                resultSize = 0;
                resultMode = MeasureSpec.UNSPECIFIED;
            }
            break;
        }
        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
    }

Insert picture description hereFor the above table, here is a specific explanation:

  • For the application layer View, its MeasureSpec is jointly determined by the parent container's MeasureSpec and its own LayoutParams
  • For different parent containers and different LayoutParams of the view itself, the view can have multiple MeasureSpecs.
  1. When the view uses a fixed width and height, no matter what the MeasureSpec of the parent container is, the MeasureSpec of the view is in the precise mode and its size follows the size in Layoutparams;
  2. When the width and height of the view is match_parent, at this time if the mode of the parent container is the precision mode, then the view is also the precision mode and its size is the remaining space of the parent container. If the parent container is the largest mode, then the view is also the largest mode and its size Will not exceed the remaining space of the parent container;
  3. When the width and height of the view is wrap_content, no matter whether the mode of the parent container is accurate or maximized, the mode of the view is always maximized and the size cannot exceed the remaining space of the parent container.
  4. Unspecified mode, this mode is mainly used in the case of multiple measurements inside the system. Generally speaking, we don't need to pay attention to this mode (note that the case of custom View placed in ScrollView needs to be processed).

Guess you like

Origin blog.csdn.net/weixin_41477306/article/details/107128448