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

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  = 101.599976   时,   getDimensionPixelSize   四舍五入后为 102,    getDimensionPixelOffset  直接强转为101.

 

在getDimension  = 101.19995   时,   getDimensionPixelSize   四舍五入后为 101,    getDimensionPixelOffset  直接强转为101.

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

你可能感兴趣的:(Android 自定义View时 getDimension, getDimensionPixelOffset, getDimensionPixelSize 三个方法的区别)