Android 关于自定义属性.
自定义属性的步骤
1. 自定义一个CustomView(extends View) 类
2. 编写values/attrs.xml, 在其中编写styleable和item等标签元素
3. 在布局文件中CustomView使用自定义的属性。
4. 在CustomView的构造方法中通过TypedArray获取。
常见的例子
自定义属性的声明文件
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="test"> <attr name="text" format="string"/> <attr name="testAttr" format="integer"/> </declare-styleable> </resources>
自定义View类
public class MyTextView extends View { private static final String TAG = MyTextView.class.getSimpleName(); public MyTextView (Context context, AttributeSet attrs) { super(context, attrs); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.test); String text = ta.getString(R.styleable.test_testAttr); int textAttr = ta.getInteger(R.styleable.test_text, -1); Log.e(TAG, "text = " + text + ",testAttr=" + textAttr); ta.recycle(); } }
布局文件里面:
<RelativeLayout xmln: android="http://schemes.android.com/apk/res/android" xmlns:tools="http:schemes.android.com/tools" xmlns:cus="http://schemes.android.com/apk/res/com.example.test" android:layout_width="match_parent" android:layout_height="match_parent"? <com.example.test.MyTextView android:layout_width="100dp" android:layout_height="200dp" cus:testAttr="520" cus:text="helloworld" /> </RelativeLayout>
结果是:
MyTextView: text = helloworld , textAttr = 520
分析: styleable的name写的是test,所以不要求一定是自定义view的名字。
AttributeSet与TypedArray
构造方法里面有个参数叫做
AttributeSet
,包含的参数的集合 ,能不能通过它去获取我的自定义属性呢?
首先AttributeSet
中确保存的是该view声明的所有的属性。并且外面的确可以通过它去获取(自定义的)
属性。看AttributeSet
的方法就明白了,如下:
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
int count = atts.getAttributeCount();
for (int i = 0; i < count; i++) {
String attrName = attrs.getAttributeName(i);
String attrVal = attrs.getAttributeValue(i);
Log.e(TAG, "attrName = " + attrName + ",attrVal = " + attrVal);
}
//=>use typedArray...
}
输出:
MyTextView(4136): attrName = layout_width , attrVal = 100.0dip
MyTextView(4136): attrName = layout_height , attrVal = 200.0dip
MyTextView(4136): attrName = text , attrVal = helloworld
MyTextView(4136): attrName = testAttr , attrVal = 520
获取到了所以属性。通过AttributeSet
可以获得布局文件中定义的所以属性的key和value.TypedArray
的用处:
通过修改布局文件,发现当布局文件里面的属性是:@dimen
或是@string
…,
利用AttributeSet
获取到的为数字串,不是我们想要的,而利用TypedArray
可以获取到原值。TypedArray
是用来简化工作的,利用AttributeSet
第一步获取到id,再去解析id,TypedArray
简化了这个工作。
利用AttributeSet
获取最终值的代码:
int widthDimensionId = attrs.getAttributeResourceValue(0, -1);
Log.e(TAG, "layout_width=" + getResources().getDimension(widthDimensionId));
declare-styleable
在布局文件里面有一个属性是:cus:text
. 系统里自带的属性是android:text
,
当然也可以利用它,例如:
在attrs.xml中:
<declare-styleable name="test">
<attr name="android:text"/>
<attr name="testAttr" format="integer"/>
</declare-styleable>
注意到这里不需要为
android:text
设置format属性。
同时意识到:声明和使用的区别是有没有format
.
然后在类中获取:ta.getString(R.styleable.test_android_text);
布局文件里面直接:android:text="helloworld"
.
系统中定义的属性,可以在
sdk/platforms/android-xx/data/res/values
该目录下看到系统中定义的属性。同时可以在系统提供的view(eg:TextView)的构造
方法中发现TypedArray获取属性的代码。是否需要
declare-styleable
这个标签
可以不用,attrs.xml为:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="testAttr" format="integer"/>
</resources>
在MyTextView
public class MyTextView extends View {
private static final String TAG = MyTextView.class.getSimpleName();
private static final int[] mAttr = {android.R.attr.text, R.attr.testAttr};
private static final int ATTR_ANDROID_TEXT = 0;
private static final int ATTR_TESTATTR = 1;
private MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
//=>use typedArray
TypedArray ta = context.obtainStyledAttributes(attrs, mAttr);
String text = ta.getString(ATTR_ANDROID_TEXT);
int textAttr = ta.getInteger(ATTR_TESTATTR, -1);
//输出:text = hello world, textAttr = 520;
Log.e(TAG, "text = " + text + ", textAttr = " + textAttr);
ta.recycle();
}
}
声明了一个int数组,数组中的元素是我们想要获取的attr的id,而且定义了两个整型
常量代表其下标,通过TypedArray
进行获取,ta.getString(0)
.
说明:
R.styleable.test => mAttr
R.styleable.test_text => ATTR_ANDROID_TEXT(0)
R.styleable.test_testAttr => ATTR_TEXTATTR(1);
在android内部,默认会这莫做,它会在R.java生成如下代码:
public static final class attr {
public static final int testAttr = 0x7f0100a9;
}
public static final class styleable {
public static final int test_android_text = 0;
public static final int test_testAttr = 1;
public static final int[] test = {0x0101014f, 0x7f0100a9};
}
styleable的出现,系统可以为我们完成很多常量(int[]数组,下标常量) 等
的编写,简化我们的开发工作。
declare-styleable
的name属性,一般是自定义View的类名,这样更加直观。
总结:
- att.xml 里面的
declare-styleable
以及item
, android会根据其在R.java中生成一些常量方便我们使用,本质上,可以不声明declar-styleable
,仅仅声明所需的属性即可。 - 在view的构造方法中,可以通过
AttributeSet
去获得自定义属性的值,但是比较麻烦,而TypedArray
可以很方便的便于获取。 - 自定义view的时候,可以使用系统已经定义的属性。
参考zhy的博客
chenzhao@hustunique.com