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型.

猜你喜欢

转载自blog.csdn.net/xujian197/article/details/82784144