自定义View解惑 为什么默认情况下设置wrap

自定义View解惑 为什么默认情况下设置wrap,第1张

自定义View解惑 为什么默认情况下设置wrap

在我们自定义View的时候,在默认情况下,也就是继承View之后,什么都不干。我们设置这个自定义的View的宽高都为wrap_content。

public class CustomView extends View {
    public CustomView(Context context) {
        super(context);
    }

    public CustomView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}



    



我们发现View填充了父View,也就是相对于match_parent的效果,这是为什么呢?
要想弄明白为什么。我们需要知道默认情况下,View是怎么设置这个大小的。

onMeasure的默认实现就是下面这几行代码

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

getDefaultSize是我们的关键代码,这个方法是一个工具方法,因为在自定义View的时候需要从measureSpec读取出size和mode,并且还要根据mode做判断,宽高都一样的流程,所以做了一个封装。

    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;
    }

这里有个关键点是MeasureSpec.AT_MOST是没有break语句的,也就是说AT_MOST和EXACTLY走的是同一段代码。AT_MOST对应wrap_content,EXACTLY对应match_parent和固定值。所以wrap_content和match_parent一个效果。这也就回答了为什么wrap_content和match_parent是一个效果。

这里就不得不引申出一个问题?为什么EXACTLY能够实现match_parent的效果?
从上面的代码可以看到,关键就在于specSize这个变量。

 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:
            if (childDimension >= 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:
            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;
        }
        //Undefine的代码
        //...
        //noinspection ResourceType
        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
    }

这里最关键的是获取size这行代码,size指的是父View还有多少空间让子View填充。switch判断里面的每个case都要做三个判断,是固定值,LayoutParams.MATCH_PARENT还是LayoutParams.WRAP_CONTENT。因为用户在xml里面设置的方式就这三种,所以都要判断,不过在MeasureSpec.AT_MOST还是在MeasureSpec.EXACTLY里面,都是赋值为这个size,也就是填充父布局大小,实现的效果也就是所谓的match_parent了。

 int size = Math.max(0, specSize - padding);

参考:https://cloud.tencent.com/developer/article/1394231

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5717281.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存