一、前言
我们在自定义控件的时候,通过 TypeArray(其实Resources 类也有这个方法,等等说。)的 getDimension、 getDimensionPixelSize 、getDimensionPixelOffset 可以获取到尺寸,然后,懵逼了。
二、源码
2.1 下面会分别贴出 TypeArray 中的三个方法的源码,加了简单的中文翻译,稍微扫一眼就ok了,看看我的翻译就先过去
2.2 getDimension 的源码,保留了源码中的原始说明,毕竟我翻译的很low,自己看不下去但是又翻译不好。
/**
* Retrieve a dimensional unit attribute at <var>index</var>. Unit
* conversions are based on the current {@link DisplayMetrics}
* associated with the resources this {@link TypedArray} object
* came from.
*
* 通过指定的 参数inde 获得一个尺寸的单位属性。该单位转换是基于你当前机器屏幕的DisplayMetrics
* 以及和当前TypedArray 的对象持有的资源而得到的,
* <p>
* 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 <var>index</var> 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 类型了)
* <p>
* 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 <var>index</var> 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一样,也涉及到简单的转换(怎么转换呢,其实是四舍五入成整形了)
* <p>
* 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</span>==>44
09-07 03:34:50.231 25181-25181/com.example.test1 E/WaterFallLayout:getDimensionPixelOffset</span>==>43
五、结论
5.1 三个方法 区别就是 返回值类型不同,getDimension 返回float getDimensionPixelOffset 强转为int,而 getDimensionPixelSize 是四舍五入。
本文详细解析了Android开发中TypeArray的getDimension、getDimensionPixelOffset和getDimensionPixelSize三个方法的源码及区别。通过源码分析和简单验证,总结出这三个方法的主要差异在于返回值类型:getDimension返回float,getDimensionPixelOffset强转为int,getDimensionPixelSize则是四舍五入后的int值。
4827

被折叠的 条评论
为什么被折叠?



