自定义View时,默认情况下设置wrap_content和match_parent一个效果解惑?

131 阅读1分钟

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

class WrapContentView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:ignore="MissingDefaultResource">

    <wrapcontentview.WrapContentView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#2979FF" />
</LinearLayout>

就这样,我们运行效果最终View填充了父View,也就是和match_parengt的效果一样,下面我们来分析下原因。 首先我们需要知道在默认情况下,View是怎么设置这个大小的。

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

其中setMeasureDimension是设置View宽高的,getDefaultSize是个关键方法,我们接下来看下这个它的源码:

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

从这显然可以看出来了,当specMode为AT_MOST和EXACTLY时候,它们走的是同一段代码result=specSize;这也就是wrap_content和match_parent是一个效果的原因。