在我们平时写布局文件的时候会用到很多属性,这是系统帮我们定义好的一些属性,这些属性在\sdk\platforms\android-XX\data\res\valus目录下,这是系统自带的所有属性。如下就是一些常用到的系统自带属性:
因为所有的控件都是View的子类,所以View定义的属性所有的控件都能使用,但是View的子类,如TextView、ImageView定义的属性,就只能他自己使用了。所以如果系统现有的属性不能满足我们的需求,就需要我们来自定义属性了。
如何自定义属性
上图中,attr标签后面有带format属性的,有不带format属性的,如果带format属性就是在定义属性,如果不带format属性就是在使用已有的属性,其中name的值就是属性的名字,format是限定当前定义的属性能接受什么值,一共有string、color、demension、integer、enum、reference、float、boolean、fraction、flag这几种类型。举个例子,比如系统已经定义了android:text属性,我们继承View自定义控件(如果是继承TextView自定义的属性,TextView中本身就有这种属性,就不需要再定义了)也需要一个文本的属性,可以有两种方式:
第一种:我们自己定义一个名为text(或者其他名称,属性名称可以随便起)的属性
<attr name="text" format="string" />
第二种:我们不自己定义属性,只需要在自定义属性中申明,我要使用这个属性(注意加上android命名空间,这样才知道使用的是系统的某个属性)
<declare-styleable name="MyTextView">
<attr name="android:text"/>
</declare-styleable>
format属性值类型:
1、reference:参考某一资源ID
属性定义:
<declare-styleable name="MyTextView">
<attr name="src" format="reference" />
</declare-styleable>
属性使用:
<com.example.customviewattribute.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:src="@drawable/ic_launcher_background"/>
2、color:颜色值
属性定义:
<declare-styleable name="MyTextView">
<attr name="color" format="color"/>
</declare-styleable>
属性使用:
<com.example.customviewattribute.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:color="@color/colorAccent"/>
3、boolean:布尔值
属性定义:
<declare-styleable name="MyTextView">
<attr name="canSelect" format="boolean"/>
</declare-styleable>
属性使用:
<com.example.customviewattribute.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:canSelect="@color/colorAccent"/>
4、dimension:尺寸值
属性定义:
<declare-styleable name="MyTextView">
<attr name="size" format="dimension"/>
</declare-styleable>
属性使用:
<com.example.customviewattribute.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:size="@dimen/dp_10"/>
5、float:浮点值
属性定义:
<declare-styleable name="MyTextView">
<attr name="alpha" format="float"/>
</declare-styleable>
属性使用:
<com.example.customviewattribute.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:alpha="10.5"/>
6、integer:整型值
属性定义:
<declare-styleable name="MyTextView">
<attr name="count" format="integer"/>
</declare-styleable>
属性使用:
<com.example.customviewattribute.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:count="10"/>
7、string:字符串
属性定义:
<declare-styleable name="MyTextView">
<attr name="text" format="string"/>
</declare-styleable>
属性使用:
<com.example.customviewattribute.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:text="hahahahaha"/>
8、fraction:百分数
属性定义:
<declare-styleable name="MyTextView">
<attr name="transparency" format="fraction"/>
</declare-styleable>
属性使用:
<com.example.customviewattribute.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:alpha="20%"/>
9、enum:枚举值
属性定义:
<declare-styleable name="MyTextView">
<attr name="orientation">
<enum name="vertical" value="0" />
<enum name="horizontal" value="1" />
</attr>
</declare-styleable>
属性使用:
<com.example.customviewattribute.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:orientation="vertical" />
10、flag:位或运算
属性定义:
<declare-styleable name="MyTextView"> <attr name="gravity"> <flag name="top" value="0x30"/> <flag name="left" value="0x03"/> <flag name="bottom" value="0x50"/> <flag name="right" value="0x05"/> </attr> </declare-styleable>
属性使用:
<com.example.customviewattribute.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:gravity="top|left" />
这10种类型可以组成混合类型,属性定义时指定多种类型值。
属性定义:
<declare-styleable name="MyTextView">
<attr name="background" format="reference|color"/>
</declare-styleable>
在类中获取属性值
在构造方法中获取属性值:
public class MyTextView extends View {
public MyTextView(Context context) {
this(context,null);
}
public MyTextView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta=context.obtainStyledAttributes(attrs,R.styleable.MyTextView);
String text=ta.getString(R.styleable.MyTextView_text);
int color=ta.getColor(R.styleable.MyTextView_color, Color.BLUE);
int size=ta.getDimensionPixelSize(R.styleable.MyTextView_size,10);
//回收TypedArray
ta.recycle();
Log.i("rx","text="+text);
Log.i("rx","color="+color);
Log.i("rx","size="+size);
}
}
AttributeSet、TypedArray和declare-styleable
AttributeSet:
在上边的构造方法中获取属性值的时候,我们看到AttributeSet和TypedArray两个类,AttributeSet是属性的集合,它的内部就是一个XML解析器,帮我们将布局文件中该控件的所有属性解析出来,并以key-value的键值对形式维护起来。
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
for (int i = 0; i < attrs.getAttributeCount(); i++) {
Log.i("rx", "attrName=" + attrs.getAttributeName(i) +
" attrValue=" + attrs.getAttributeValue(i));
}
}
打印的结果是:
rx: attrName=layout_width attrValue=100.0dip
rx: attrName=layout_height attrValue=100.0dip
rx: attrName=color attrValue=@2130968615
rx: attrName=size attrValue=20.0dip
rx: attrName=text attrValue=测试数据
我们看到,通过AttributeSet获取属性的值的时候,它会将我们布局文件中的值原原本本的获取出来:比如宽度=100.0dip,如果我们需要使用这个宽度的话,需要把dip去掉,然后转换成整形、color获取到的是一个资源ID,需要我们自己通过ID获取到真正的颜色。
TypedArray:
使用TypedArray,获取到的就是我们真正需要的不需要再做转换的值:
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyTextView">
<attr name="color" format="color" />
<attr name="android:layout_width" />
<attr name="android:layout_height" />
</declare-styleable>
</resources>
布局文件:
<com.example.customviewattribute.MyTextView
android:layout_width="100dp"
android:layout_height="100dp"
app:color="@color/colorPrimary" />
自定义View:
public class MyTextView extends View {
public MyTextView(Context context) {
this(context, null);
}
public MyTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta=context.obtainStyledAttributes(attrs,R.styleable.MyTextView);
int color=ta.getColor(R.styleable.MyTextView_color,Color.BLUE);
float width=ta.getDimension(R.styleable.MyTextView_android_layout_width,200);
float height=ta.getDimension(R.styleable.MyTextView_android_layout_height,200);
Log.i("rx","color="+color);
Log.i("rx","width="+width);
Log.i("rx","height="+height);
}
}
输出结果是:
rx: color=-16743049
rx: width=150.0
rx: height=150.0
可以看到,通过TypedArray方式获取的属性,拿到的就是我们想要的值。
declare-styleable:
所有的资源文件在R中都会对应一个整形常量,我们可以通过这个ID值找到资源文件。属性在R中对应的类是public static final class attr,如果我们写了declare-styleable,在R文件中就会生成styleable类,这个类其实就是将每个控件的属性分组,然后记录属性的索引值,而TypedArray正好需要通过此索引值获取属性。