从源码看getDimension()、getDimensionPixelOffset()以及getDimensionPixelSize()三个区别

     一、前言

我们在自定义控件的时候,通过 TypeArray(其实Resources 类也有这个方法,等等说。)的 getDimension、 getDimensionPixelSize 、getDimensionPixelOffset 可以获取到尺寸,然后,懵逼了。

     二、源码

2.1 下面会分别贴出 TypeArray 中的三个方法的源码,加了简单的中文翻译,稍微扫一眼就ok了,看看我的翻译就先过去

2.2  getDimension  的源码,保留了源码中的原始说明,毕竟我翻译的很low,自己看不下去但是又翻译不好。

    /**
     * Retrieve a dimensional unit attribute at index. Unit
     * conversions are based on the current {@link DisplayMetrics}
     * associated with the resources this {@link TypedArray} object
     * came from.
     *
     * 通过指定的 参数inde 获得一个尺寸的单位属性。该单位转换是基于你当前机器屏幕的DisplayMetrics
     * 以及和当前TypedArray 的对象持有的资源而得到的,
     * 

* This method will throw an exception if the attribute is defined but is * not a dimension. * 当属性不是尺寸的时候,即使确实被定义了,也会抛出一个异常的。 * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined or * not a resource. * * @return Attribute dimension value multiplied by the appropriate * metric, or defValue if not defined. * 结果将被乘上一个合适的 metric * @throws RuntimeException if the TypedArray has already been recycled. * 如果当前TypedArray 被recycle 会抛异常 * @throws UnsupportedOperationException if the attribute is defined but is * not an integer. * 如果定义的属性不是整形,会抛异常 * * @see #getDimensionPixelOffset * @see #getDimensionPixelSize */ public float getDimension(int index, float defValue) { if (mRecycled) { throw new RuntimeException("Cannot make calls to a recycled instance!"); } 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*AssetManager.STYLE_NUM_ENTRIES, value); throw new UnsupportedOperationException( "Failed to resolve attribute at index " + index + ": " + value); } throw new UnsupportedOperationException("Can't convert to dimension: type=0x" + Integer.toHexString(type)); } }



2.3 getDimensionPixelOffset 的源码

 /**
     * Retrieve a dimensional unit attribute at index for use
     * as an offset in raw pixels.  This is the same as
     * {@link #getDimension}, except the returned value is converted to
     * integer pixels for you.  An offset conversion involves simply
     * truncating the base value to an integer.
     *
     * 通过 参数 index 获取一个在原始像素上使用一个偏移(offset)尺寸单位。除了返回值类型是整形(单位是像素),
     * 其他的和getDimension一样,偏移也涉及到简单的转换(怎么转换呢,其实就是强转为int 类型了)
     * 

* This method will throw an exception if the attribute is defined but is * not a dimension. * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined or * not a resource. * * @return Attribute dimension value multiplied by the appropriate * metric and truncated to integer pixels, or defValue if not defined. * @throws RuntimeException if the TypedArray has already been recycled. * @throws UnsupportedOperationException if the attribute is defined but is * not an integer. * * @see #getDimension * @see #getDimensionPixelSize */ public int getDimensionPixelOffset(int index, int defValue) { if (mRecycled) { throw new RuntimeException("Cannot make calls to a recycled instance!"); } 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*AssetManager.STYLE_NUM_ENTRIES, value); throw new UnsupportedOperationException( "Failed to resolve attribute at index " + index + ": " + value); } throw new UnsupportedOperationException("Can't convert to dimension: type=0x" + Integer.toHexString(type)); }


2.4 getDimensionPixelSize 的源码

/**
     * Retrieve a dimensional unit attribute at index for use
     * as a size in raw pixels.  This is the same as
     * {@link #getDimension}, except the returned value is converted to
     * integer pixels for use as a size.  A size conversion involves
     * rounding the base value, and ensuring that a non-zero base value
     * is at least one pixel in size.
     * 通过 参数 index 获取一个在原始像素上的尺寸单位。除了返回值类型是整形(单位是像素),
     * 其他的和getDimension一样,也涉及到简单的转换(怎么转换呢,其实是四舍五入成整形了)
     * 

* This method will throw an exception if the attribute is defined but is * not a dimension. * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined or * not a resource. * * @return Attribute dimension value multiplied by the appropriate * metric and truncated to integer pixels, or defValue if not defined. * @throws RuntimeException if the TypedArray has already been recycled. * @throws UnsupportedOperationException if the attribute is defined but is * not a dimension. * * @see #getDimension * @see #getDimensionPixelOffset */ public int getDimensionPixelSize(int index, int defValue) { if (mRecycled) { throw new RuntimeException("Cannot make calls to a recycled instance!"); } 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*AssetManager.STYLE_NUM_ENTRIES, value); throw new UnsupportedOperationException( "Failed to resolve attribute at index " + index + ": " + value); } throw new UnsupportedOperationException("Can't convert to dimension: type=0x" + Integer.toHexString(type)); }


三、分析

3.1从上面的三段源码来看,我们应该看到这一段。这三句就是三个方法的区别,追进去看下吧。

return TypedValue.complexToDimension(
                data[index + AssetManager.STYLE_DATA], mMetrics);
        return TypedValue.complexToDimensionPixelOffset(
                data[index + AssetManager.STYLE_DATA], mMetrics);
        return TypedValue.complexToDimensionPixelSize(
                data[index + AssetManager.STYLE_DATA], mMetrics);


上面三段代码对应以下的三个方法,可以看出返回值上的区别了。

     

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

    public static int complexToDimensionPixelOffset(int data,
                                                    DisplayMetrics metrics) {
        /**
         * 这里只是强转,相当于调用了 return (int)complexToDimension(data,metrics)
         */
        return (int) applyDimension(
                (data >> COMPLEX_UNIT_SHIFT) & COMPLEX_UNIT_MASK,
                complexToFloat(data),
                metrics);
    }

    public static int complexToDimensionPixelSize(int data,
                                                  DisplayMetrics metrics) {
        final float value = complexToFloat(data);
        /**
         * 这一步相当于  f = complexToDimension(data,metrics),下面就是将f 变化了
         */
        final float f = applyDimension(
                (data >> COMPLEX_UNIT_SHIFT) & COMPLEX_UNIT_MASK,
                value,
                metrics);
        /**
         * 这一步就是四舍五入
         */
        final int res = (int) (f + 0.5f);
        if (res != 0) return res;
        if (value == 0) return 0;
        if (value > 0) return 1;
        return -1;
    }

好了,至此我们就简单的看了三个方法的区别,另外再补充说下,开头说到 的 Resources 类中三个相应的方法,最终也是这里的区别,这里就不多说了。

四,简单的验证

4.1 自定义控件(省略)

4.2 自定义属性 (省略)

4.3 在自定义控件中获取属性值

 private void init(Context context, AttributeSet attrs) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.WaterFallLayout);
        mColums = array.getInteger(R.styleable.WaterFallLayout_colum, DEFAULT_COLUMS);
        float dimension = array.getDimension(R.styleable.WaterFallLayout_margin,DEFAULT_MARGIN);
        int pixelSize = array.getDimensionPixelSize(R.styleable.WaterFallLayout_margin,DEFAULT_MARGIN);
        int pixelOffset = array.getDimensionPixelOffset(R.styleable.WaterFallLayout_margin,DEFAULT_MARGIN);
        array.recycle();

        Log.e(TAG, "getDimension==>" + dimension);
        Log.e(TAG, "getDimensionPixelSize==>" + pixelSize);
        Log.e(TAG, "getDimensionPixelOffset==>" + pixelOffset);
    }


          4.4 在布局文件中引用该自定义控件(省略,布局中传入margin 参数值是14.5dp),运行得到下面结果

                09-07 03:34:17.223 25181-25181/com.example.test1 E/WaterFallLayout:getDimension==>43.5
09-07 03:34:17.223 25181-25181/com.example.test1 E/WaterFallLayout:getDimensionPixelSize==>44
09-07 03:34:50.231 25181-25181/com.example.test1 E/WaterFallLayout:getDimensionPixelOffset==>43

、结论

5.1 三个方法 区别就是 返回值类型不同,getDimension 返回float    getDimensionPixelOffset 强转为int,而 getDimensionPixelSize 是四舍五入。


你可能感兴趣的:(android)