欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

自定义View

程序员文章站 2022-05-30 20:26:52
...

MeasureSpec哪里来的

自定义View

ViewGroup.java getChildMeasureSpec()
    //测量子view
    protected void measureChild(View child, int parentWidthMeasureSpec,
            int parentHeightMeasureSpec) {
        //子view的宽高 match_parent wrap_content 或者具体数值
        final LayoutParams lp = child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                mPaddingLeft + mPaddingRight, lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                mPaddingTop + mPaddingBottom, lp.height);

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

    //Spec父容器对子view的要求
    //padding子view的padding
    //childDimension 子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);//如果padding的尺寸比父类给的尺寸还大就用0

        int resultSize = 0;
        int resultMode = 0;

        switch (specMode) {
        //父容器为精确模式 知道自己的具体尺寸
        // Parent has imposed an exact size on us
        case MeasureSpec.EXACTLY:
            //子view设置了具体的值 入layout_width = "100dp"
            // 则使用子类设置的值 测量模式使用精确
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            }
            //子view想和父容器一样大
            //使用父容器的尺寸 测量模式为精确
            else if (childDimension == LayoutParams.MATCH_PARENT) {
                resultSize = size;
                resultMode = MeasureSpec.EXACTLY;
            }
            //子view想用自己的尺寸 但是他的大小不能超过父容器大小 所以resultSize使用父容器大小
            //子view的模式就是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;

        //父容器 测量模式为最大模式的话,即父容器不知道自己的尺寸,但是大小不能超过size
        case MeasureSpec.AT_MOST:
            //子View知道自己的尺寸 使用子view的尺寸 精确模式
            if (childDimension >= 0) {
                // Child wants a specific size... so be it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            }
            //子viwe想和父容器一样大,使用父容器的尺寸 最大模式
            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;
            }
            //子view想使用自己的最小值
            //让子view自己测量 但最大不能超过父容器size
            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;//让子view自己决定
                resultMode = MeasureSpec.EXACTLY;
            }
            //子类想和父容器一样大,但是父容器不知道知己的尺寸,所以子view设置为0
            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;
            }
            //child 希望尺寸由自己决定,一般这个时候,父容器 会给它一个 Size 作为最大值限制,  
            //但是 父容器 本身也需要计算,所以只能设置为0,并且没有给child最大值的设定  
            //将child的测量模式设置为 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);
    }

 

 

相关标签: 自定义view