昨天遇到并解决的需求,以此文记录,供遇到同类问题的同仁参考!
需求描述
不引用R类获取到自定义样式的值(资源id数组),如下是R.java中某个自定义样式的值
public static final int[] LoadingView = { 0x7f0200ac, 0x7f0200c5, 0x7f0200cd, 0x7f0200ce, 0x7f0200cf };
即如下代码如示,在自定义view组件中,获取自定义样式的值时不能使用R.styleable
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.drop_down_list_attr);
mIsOnBottomStyle = ta.getBoolean(R.styleable.drop_down_list_attr_isOnBottomStyle, false);
mIsAutoLoadOnBottom = ta.getBoolean(R.styleable.drop_down_list_attr_isAutoLoadOnBottom, false);
解决方案
通过资源字符串获取资源id的方式获取自定义样式各个项的资源id值
示例代码如下
public MyLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
/**
int a = R.attr.loadding_color;
int b = R.attr.ring_style;
int styleAttrId[] = R.styleable.LoadingView;
a == styleAttrId[0]
b == styleAttrId[2]
**/
Resources res = context.getResources();
int styleAttrIdArray[] = new int[2]; //LoadingView的属性项的个数,示例中仅有两个
styleAttrIdArray[0] = res.getIdentifier("loadding_color", "attr", context.getPackageName());
styleAttrIdArray[1] = res.getIdentifier("ring_style", "attr", context.getPackageName());
//TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LoadingView, 0, 0);
TypedArray a = context.obtainStyledAttributes(attrs, styleAttrIdArray, 0, 0);
//如下的R.styleable.LoadingView_loadding_color,LoadingView_ring_style是索引常量,在R.java类中查看替换即可
setColor(a.getInt(R.styleable.LoadingView_loadding_color, -12871201));
setRingStyle(a.getInt(R.styleable.LoadingView_ring_style, 0));
//setColor, setRingStyle这里是自定义方法
}
技术原理
关键点:自定义样式所有属性项的值(资源ID数组)其实都是存放在资源类R的内部attr类的!
如下是某个自定义样式
<declare-styleable name="LoadingView">
<attr format="color" name="loadding_color"/>
<attr format="enum" name="ring_style">
<enum name="square" value="0"/>
<enum name="round" value="1"/>
</attr>
<attr format="enum" name="progress_style">
<enum name="material" value="0"/>
<enum name="linear" value="1"/>
</attr>
<attr format="dimension" name="ring_width"/>
<attr format="dimension" name="ring_radius"/>
</declare-styleable>
生成的R类,对应字段如下
对应的某个属性项在R类的attr区,如下所示
解决方案二
有时候方案一会失效,原因是“打包”后的资源文件中自定义属性的排序与你“看到的”R文件中的排序不一致,解决方案是对自定义属性id值的数据做排序,并动态获取自定义属性的索引值,代码如下所示
int id1 = res.getIdentifier("loadding_color", "attr", context.getPackageName());
int id2 = res.getIdentifier("ring_style", "attr", context.getPackageName());
int styleAttrIdArray[] = new int[2]; //LoadingView的属性项的个数,示例中仅有两个
styleAttrIdArray[0] = id1;
styleAttrIdArray[1] = id2;
//排序一下
Arrays.sort(styleAttrIdArray);
int ringStyleAttrIndex = Arrays.binarySearch(styleAttrIdArray, id1);
int loaddingAttrIndex = Arrays.binarySearch(styleAttrIdArray, id2);
//TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LoadingView, 0, 0);
TypedArray a = context.obtainStyledAttributes(attrs, styleAttrIdArray, 0, 0);
//如下的R.styleable.LoadingView_loadding_color,LoadingView_ring_style是索引常量,在R.java类中查看替换即可
setColor(a.getInt(loaddingAttrIndex, -12871201));
setRingStyle(a.getInt(ringStyleAttrIndex, 0));
//setColor, setRingStyle这里是自定义方法