自定义View时wrap_content属性无效的处理方法

最近在学习自定义View,在这里对学到的一些东西做个记录,来加深一下记忆。

首先看View的onMeasure方法

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

这里面有主要有两个方法其中setMeasuredDimension方法是设置View的宽高的,而使wrap_content属性无效的原因要看第二个方法就是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;
    }

在这里还要说一下getDefaultSize传入的两个参数getSuggestedMinimumWidth(), widthMeasureSpec,这里了解一下宽的,高是一样的。

其中getSuggestedMinimumWidth方法源码如下:

protected int getSuggestedMinimumWidth() {
        return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
    }

意思大概就是如果View没背景就返回mMinWidth,如果View设置了背景就返回mMinWidth和mBackground的最小宽度之间最大的那一个。

widthMeasureSpec则是一个32位的int值,它的高2位代表了SpecMode,低30位代表了SpecSize;其中SpecMode指的是测量模式,SpecSize指的是测量大小,而SpecMode只有三种模式分别是UNSPECIFIED、AT_MOST和EXACTLY。这种模式的大致含义如下所示:

  • UNSPECIFIED 未指定模式,View想多大就多大,父容器不做限制。
  • AT_MOST 最大模式,差不多对应wrap_content属性。
  • EXACTLY 精确模式,对应match_parent属性和具体的数值。

接下来在回过头看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://未指定模式下直接返回传进来的的size值
            result = size;
            break;
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY://AT_MOST和EXACTLY模式下都返回获取到的specSize 值
            result = specSize;
            break;
        }
        return result;
    }

可以看到AT_MOST和EXACTLY模式都返回获取到的specSize 值,即View在这两种模式下宽高都取决于specSize。由此可以知道当我们直接继承View来自定义View时,对与我们的这个自定义的View来说wrap_content和match_parent属性的效果是相同的。因此当我们直接继承View来自定义View时一定要重写onMeasure方法,来针对wrap_content属性进行处理。例如可以在onMeasure方法中给wrap_content属性指定一个默认的值,代码如下:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取宽高的测量模式
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        //获取宽高的测量大小
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        if (widthSpecMode == MeasureSpec.AT_MOST & heightSpecMode == MeasureSpec.AT_MOST) {//当宽高的测量模式都为AT_MOST时指定默认宽高900
            setMeasuredDimension(900, 900);
        } else if (widthSpecMode == MeasureSpec.AT_MOST) {//当宽的测量模式都为AT_MOST时指定默认宽900
            setMeasuredDimension(900, heightSpecSize);
        } else if (heightSpecMode == MeasureSpec.AT_MOST) {//当高的测量模式都为AT_MOST时指定默认高900
            setMeasuredDimension(widthSpecSize, 900);
        }
    }

参考自https://www.jianshu.com/p/6b7e5d2d51ab

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当父布局的高度属性为 `wrap_content` 自定义 View 的高度是根其内容动态确定的,无法直接获取准确的高度值。但可以通过以下方法来获取自定义 View 的准确高度: 1. 使用 ViewTreeObserver 监听布局完成事件:在自定义 View 的代码中,可以使用 `ViewTreeObserver` 来监听布局完成事件,一旦布局完成,就可以获取到自定义 View 的准确高度。示例代码如下: ```java ViewTreeObserver vto = customView.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { customView.getViewTreeObserver().removeOnGlobalLayoutListener(this); int height = customView.getHeight(); // 获取自定义 View 的高度 // 在这里可以使用获取到的高度进行后续操作 } }); ``` 2. 重写 `onMeasure()` 方法:在自定义 View 的代码中,可以重写 `onMeasure()` 方法,在测量过程中获取到准确的高度值,并保存起来供后续使用。示例代码如下: ```java @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); // 在这里可以获取到准确的宽度和高度,并保存起来 } ``` 通过以上方法,你可以在父布局为 `wrap_content` 的情况下获取到自定义 View 的准确高度。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值