前言
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
在layout文件中进行布局时,常常会通过像上面这样的语句来为view添加属性。这样的方式可以大大简化布局工作,并且复用性强。本文将详细讲解如何为自己的view添加自定义属性,以及这些属性是如何发挥作用的。
编写attr.xml文件
在res/values/目录下创建attrs.xml文件,在resource根标签下添加declare-styleable标签,之后就可以开始编辑自定义属性了。下面为一个示例:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyViewAttr">
<attr name="name" format="string"/>
<attr name="color" format="color"/>
<attr name="hasBackground" format="boolean"/>
<attr name="background" format="reference"/>
<attr name="size" format="dimension"/>
<attr name="gravity">
<flag name="top" value="0"/>
<flag name="center" value="1"/>
<flag name="bottom" value="2"/>
</attr>
</declare-styleable>
</resources>
首先,紧跟在declare-styleable后面的name是这个自定义属性集的名字,之后在代码中引用属性时会用到。每个属性用一个attr标签来声明,标签内的name为这个属性的名字,format为这个属性的数据格式,有以下几种:
- reference:引用其他资源。例:@drawable/bg;
- color:颜色。例:#FF0000;
- boolean:布尔值。例:false;
- dimension:尺寸值。例:100dp;
- float:浮点数。例:0.7f;
- integer:整数。例:100;
- string:字符串。例:hello world;
- fraction:百分数。例:50%
- enum:枚举值。例:<enum name=”horizontal” value=”0”>;
- flag:位。例:<flag name=”top” value=”0”/>
下面补充几点:
(1)可以将两种或多种format用|连接起来,表示都可使用。例:reference|color。
(2)为属性提供几种可选值的方法:
<attr name="gravity">
<flag name="top" value="0"/>
<flag name="center" value="1"/>
<flag name="bottom" value="2"/>
</attr>
(3)可以在resources标签下声明多个declare-styleable,但它们不能有相同名称的属性。
在layout文件中使用自定义属性
属性集编写完毕后,就可以在layout文件中引用它的内容了。为了和系统空间区分开,需要引入自己的namespace。Android Studio中只需在根布局中加上这么一行:
xmlns:custom = "http://schemas.android.com/apk/res-auto"
xmlns:后面的就是引入的namespace的名字,这里取名为custom。之后就可以通过它来引用自定义属性了。示例如下:
android:layout_width="match_parent"
android:layout_height="match_parent"
custom:name="myView"
custom:color="#FF0000"
custom:hasBackground="true"
custom:background="@drawable/bg"
custom:size="100dp"
custom:gravity="bottom"
获取自定义属性
到这里为止,自定义属性还不能发挥作用。接下来需要在自定义的view的构造器中获取它们。示例如下:
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
//获取属性集
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.MyViewAttr);
try {
//获取各个属性
String name = ta.getString(R.styleable.MyViewAttr_name);
int color = ta.getColor(R.styleable.MyViewAttr_color,Color.RED);
boolean hasBackground = ta.getBoolean(R.styleable.MyViewAttr_hasBackground,false);
Drawable background = ta.getDrawable(R.styleable.MyViewAttr_background);
int gravity = ta.getInt(R.styleable.MyViewAttr_gravity,-1);
}finally {
//回收TypedValue对象
ta.recycle();
}
}
总结一下就是这么几步:
(1)调用context.obtainStyledAttributes(attrs,R.styleable.MyViewAttr)获取TypedValue。第一个参数是构造器中的AttributeSet对象,第二个参数为通过<declare-styleable name=”MyViewAttr”>定义的属性集的名称;
(2)调用TypedValue的各种getXXX()方法获取相应的属性。部分方法需要提供默认值;
(3)属性获取完毕后,调用TypedValue的recycle()方法将其回收。
使用自定义属性
最后就是根据获取到的这些值,对view的各个属性进行设置。这个没有固定的方法,需要根据实际情况而定。