今天这个不是啥干货, 就是踩坑的一个记录,干货我最近还没想好写啥

在我们自定义View的过程中,常常会用到自定义字段,很多时候也会使用 getDimensionPixelSize() 方法来获取自定义属性的大小

今天在做一个需求的时候突然在想,为什么在Android的layout_width 这样的方法里可以使用wrap_content, match_parent 这样的方法,于是参考了下官方的代码,发现如果在在自己的工程中使用这个需要如下定义attr

<attr name="indicator_width" format="dimension">  
	<enum name="fill_parent" value="-1" />  
	<enum name="match_parent" value="-1" />  
	<enum name="wrap_content" value="-2" />  
</attr>

这之后 我就想当然的去使用平时常用的getDimensionPixelSize() 去获取取值了,结果跑起来就crash了,

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

原始的错误堆栈没了,反正就是抛了这个

分析源代码如下

/**  
 * 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. * <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(@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));  
	}

由于这里之前<enum name="wrap_content" value="-2" />定义的是个枚举类型,这里的 getDimensionPixelSize() 无法处理,就抛出了之前的异常,看了android的实现,发现他是使用getLayoutDimension()实现的,遂使用该方法代替, 成功拿到大小,并且通过ViewGroup.LayoutParams.WRAP_CONTENT进行判断即可。

好奇的我看了下getLayoutDimension()的实现方法,发现 他是刻意对TYPE_ENUM进行了判断

/**  
 * Special version of {@link #getDimensionPixelSize} for retrieving  
 * {@link android.view.ViewGroup}'s layout_width and layout_height  
 * attributes.  This is only here for performance reasons; applications * should use {@link #getDimensionPixelSize}.  
 * * @param index Index of the attribute to retrieve.  
 * @param defValue The default value to return if this attribute is not  
 *                 default or contains the wrong type of data. * * @return Attribute dimension value multiplied by the appropriate  
 *         metric and truncated to integer pixels. * @throws RuntimeException if the TypedArray has already been recycled.  
 */
 public int getLayoutDimension(@StyleableRes 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_FIRST_INT  
		&& type <= TypedValue.TYPE_LAST_INT) {  
		return data[index+AssetManager.STYLE_DATA];  
	} else if (type == TypedValue.TYPE_DIMENSION) {  
		return TypedValue.complexToDimensionPixelSize(data[index + AssetManager.STYLE_DATA], mMetrics);  
	}  
	return defValue;  
}

Written with StackEdit.