Android 自定义View时 getDimension, getDimensionPixelOffset, getDimensionPixelSize 三个方法的区别

本文详细分析了Android开发中自定义View时,getDimension、getDimensionPixelOffset和getDimensionPixelSize三个方法的区别。在未找到属性时,三者均直接返回默认值,但在处理TypedValue.TYPE_DIMENSION时有所不同。getDimension返回浮点类型值,最精确;getDimensionPixelOffset会舍去小数部分;getDimensionPixelSize则对小数部分进行四舍五入后再转换为整数。开发时需注意根据需求选择合适的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

getDimension 的源码如下

public float getDimension(@StyleableRes int index, float defValue) {
    if (mRecycled) {
        throw new RuntimeException("Cannot make calls to a recycled instance!");
    }

    final int attrIndex = index;
    index *= AssetManager.STYLE_NUM_ENTRIES;

    final int[] data = mData;
    final int type = data[index+AssetManager.STYLE_TYPE];
    if (type == TypedValue.TYPE_NULL) {
        return defValue;
    } else if (type == TypedValue.TYPE_DIMENSION) {
        return TypedValue.complexToDimension(
                    data[index + AssetManager.STYLE_DATA], mMetrics);
    } else if (type == TypedValue.TYPE_ATTRIBUTE) {
        final TypedValue value = mValue;
        getValueAt(index, value);
        throw new UnsupportedOperationException(
                    "Failed to resolve attribute at index " + attrIndex + ": " + value);
    }

    throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
                + " to dimension: type=0x" + Integer.toHexString(type));
}

getDimensionPixelOffset 的源码如下

public int getDimensionPixelOffset(@StyleableRes int index, int defValue) {
    if (mRecycled) {
    throw new RuntimeException("Cannot make calls to a recycled instance!");
    }

    final int attrIndex = index;
    index *= AssetManager.STYLE_NUM_ENTRIES;

    final int[] data = mData;
    final int type = data[index+AssetManager.STYLE_TYPE];
    if (type == TypedValue.TYPE_NULL) {
        return defValue;
    } else if (type == TypedValue.TYPE_DIMENSION) {
        return TypedValue.complexToDimensionPixelOffset(
                    data[index + AssetManager.STYLE_DATA], mMetrics);
    } else if (type == TypedValue.TYPE_ATTRIBUTE) {
        final TypedValue value = mValue;
        getValueAt(index, value);
        throw new UnsupportedOperationException(
                    "Failed to resolve attribute at index " + attrIndex + ": " + value);
    }

    throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
                + " to dimension: type=0x" + Integer.toHexString(type));
}

getDimensionPixelSize 的源码如下

public int getDimensionPixelSize(@StyleableRes int index, int defValue) {
    if (mRecycled) {
        throw new RuntimeException("Cannot make calls to a recycled instance!");
    }

    final int attrIndex = index;
    index *= AssetManager.STYLE_NUM_ENTRIES;

    final int[] data = mData;
    final int type = data[index+AssetManager.STYLE_TYPE];
    if (type == TypedValue.TYPE_NULL) {
        return defValue;
    } else if (type == TypedValue.TYPE_DIMENSION) {
        return TypedValue.complexToDimensionPixelSize(
                data[index+AssetManager.STYLE_DATA], mMetrics);
    } else if (type == TypedValue.TYPE_ATTRIBUTE) {
        final TypedValue value = mValue;
        getValueAt(index, value);
        throw new UnsupportedOperationException(
                    "Failed to resolve attribute at index " + attrIndex + ": " + value);
    }

    throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
                + " to dimension: type=0x" + Integer.toHexString(type));
}

可以看到三个方法在没有查到属性返回默认值的时候都是直接返回。不会做任何处理。所以在添加默认值的时候,如果默认值是采用的dp这种单位,记得要乘以density。
三个方法不同处在于type == TypedValue.TYPE_DIMENSION 时。这也就是在获取自定义属性的时候。我们看看三个方法的不同处

getDimension 的计算方法如下

public static float complexToDimension(int data, DisplayMetrics metrics) {
    return applyDimension(
            (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK,
            complexToFloat(data),
            metrics);
}

该方法直接返回一个float类型的值.

getDimensionPixelOffset 的计算方法如下

public static int complexToDimensionPixelOffset(int data, DisplayMetrics metrics) {
    return (int)applyDimension(
            (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK,
            complexToFloat(data),
            metrics);
}

该方法只是简单的将getDimension方法得到的值进行了一下强转.。即不管getDimension得到的值是20.1,或者是20.9。强转后都会是20。即舍去getDimension的小数。

getDimensionPixelSize 的计算方法如下.

public static int complexToDimensionPixelSize(int data, DisplayMetrics metrics) {
    final float value = complexToFloat(data);
    final float f = applyDimension(
                    (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK, value, metrics);
    final int res = (int) ((f >= 0) ? (f + 0.5f) : (f - 0.5f));
    if (res != 0) return res;
    if (value == 0) return 0;
    if (value > 0) return 1;
    return -1;
}

该方法将getDimension方法得到的值上在加上0.5f, 在进行强转。即如果getDimension得到的值为20.1,加上0.5后为20.6。强转后为20。如果getDimension得到的值为20.5,加上0.5后为30.0。强转后为30。即对getDimension得到的小数点的第一位进行四舍五入。

结果就是getDimension方法得到的返回值最为精确。getDimensionPixelOffset方法得到的返回值为舍去小数后的int型。getDimensionPixelSize 方法得到的返回值为四舍五入后的int型。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值