自定义View—测量宽高遇到的问题

例1. 缺少默认值 | 自己写的

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int finalWidth, finalHeight;

        // 不明
        finalWidth = getSuggestedMinimumWidth();
        finalHeight = getSuggestedMinimumHeight();

        if (widthMode == MeasureSpec.EXACTLY) {
            finalWidth = widthSize;
        } else if (widthMode == MeasureSpec.AT_MOST) {
            int padding = getPaddingLeft() + getPaddingRight();
            finalWidth += padding;
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            finalHeight = heightSize;
        } else if (heightMode == MeasureSpec.AT_MOST) {
            int padding = getPaddingTop() + getPaddingBottom();
            finalHeight += padding;
        }

        setMeasuredDimension(finalWidth, finalHeight);
    }

① 上面的例子中缺少默认值,所以高度为0

例2. 指定默认宽高 | 对第三种测量模式UNSPECIFIED的理解

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    int desiredWidth = 100;
    int desiredHeight = 100;

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    int width;
    int height;

    //Measure Width
    if (widthMode == MeasureSpec.EXACTLY) {
        //Must be this size
        width = widthSize;
    } else if (widthMode == MeasureSpec.AT_MOST) {
        //Can't be bigger than...
        width = Math.min(desiredWidth, widthSize);
    } else {
        //Be whatever you want
        width = desiredWidth;
    }

    //Measure Height
    if (heightMode == MeasureSpec.EXACTLY) {
        //Must be this size
        height = heightSize;
    } else if (heightMode == MeasureSpec.AT_MOST) {
        //Can't be bigger than...
        height = Math.min(desiredHeight, heightSize);
    } else {
        //Be whatever you want
        height = desiredHeight;
    }

    //MUST CALL THIS
    setMeasuredDimension(width, height);

解决的方法总结:

  1. 指定一个默认的内部宽高,例如本方法中的desiredWidth = 100。
  2. 判断当MeasureSpec的模式为AT_MOST(对应于wrap_content)时,设置结果为设置的值(最大为我们设置的值,如果小于设置值就设置为specSize)。
  3. 判断当MeasureSpec的模式为非AT_MOST时,直接设置为系统的测量值即可。
  4. 设置值没有特定的标准,以实际情况为准。

以上作者:Jinlin
链接:https://www.jianshu.com/p/95b98edda6ac

例3. 宽高默认值

     @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 
        setMeasuredDimension(measureWidth(widthMeasureSpec),
                measureHeight(heightMeasureSpec));
 
    }
 
    private int measureHeight(int measureSpec) {
        int result = 0;
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);
 
        if (mode == MeasureSpec.EXACTLY) {
            result = size;
        } else {
            result=75;
            if (mode == MeasureSpec.AT_MOST) {
                result = Math.min(result, size);
            }
        }
        return result;
 
    }
 
    private int measureWidth(int measureSpec) {
        int result = 0;
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);
 
        if (mode == MeasureSpec.EXACTLY) {
            result = size;
        } else {
            result = 75;//根据自己的需要更改
            if (mode == MeasureSpec.AT_MOST) {
                result = Math.min(result, size);
            }
        }
        return result;
 
    }



③ UNSPECIFIED 这种模式不指定测量模式,view大小没有限制,想多大就多大。

版权声明:本文为CSDN博主「mxiaoyem」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/mxiaoyem/article/details/51077054

另外(https://www.cnblogs.com/wjtaigwh/p/6600035.html)

如果我们的自定义控件在布局文件中,只需要设置指定的具体宽高,或者MATCH_PARENT 的情况,我们可以不用重写onMeasure方法。

但如果自定义控件需要设置包裹内容WRAP_CONTENT ,我们需要重写onMeasure方法,为控件设置需要的尺寸;默认情况下WRAP_CONTENT 的处理也将填充整个父控件。

onMeasure方法最后需要调用setMeasuredDimension方法来保存测量的宽高值。

题外话

例1中,发现在onMeasure()里最终确定宽高时调用setMeasuredDimension()。
在onSizeChanged()中getMeasuredWidth()/getMeasuredHeight(),get方法得到的数值应该就是onMeasure()中set方法确定的。


set()/get()

// 点进去看看源码就知道了


setMeasuredDimension()一直往里点
getMeasuredWidth()

你可能感兴趣的:(自定义View—测量宽高遇到的问题)