概述
在我們自定義view的時(shí)候,一般會(huì)用到自定義屬性,來(lái)做view的屬性配置(比如:顯示控制,dis/enable狀態(tài)等)。
自定義屬性的步驟如下
- 創(chuàng)建一個(gè)attr.xml,在styleable標(biāo)簽里自定義所需要的屬性
- 在布局xml文件中使用自定義view,配置自定義屬性的值
- 在自定義view中,通過(guò)TypedArray對(duì)象,獲取自定義屬性的值,然后控制view的行為
這篇文章就講一講,以上3個(gè)步驟中容易忽略的事情,并且以自定義導(dǎo)航欄為例來(lái)做講解。
AttributeSet
前提條件:
http://schemas.android.com/apk/res-auto是自定義屬性值的namespace,也就是要在布局xml文件中使用自定義屬性標(biāo)簽時(shí)需要聲明的namespace
http://schemas.android.com/apk/res/android是系統(tǒng)默認(rèn)的namespace,以android:開(kāi)頭
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:navibar="http://schemas.android.com/apk/res-auto"
...
<com.example.hly.attrdemo.NavigationBar
android:layout_width="wrap_content"
android:layout_height="35dp"
navibar:leftText="back"
navibar:leftImage="@drawable/vr_back"/>
</RelativeLayout>
在我們的自定義view的構(gòu)造方法中有一個(gè)參數(shù)是AttributeSet。
從名字上看是屬性值的一個(gè)set集合,那在xml中設(shè)置了自定義屬性值后,能通過(guò)AttributeSet獲取配置的值,不通過(guò)TypedArray嗎?試一試先。
int attrsCount = attrs.getAttributeCount();
Log.i(TAG, "AttributeSet size :" + attrsCount);
for (int i = 0; i < attrsCount; i++) {
String name = attrs.getAttributeName(i);
String value = attrs.getAttributeValue("http://schemas.android.com/apk/res-auto", name);
if (TextUtils.isEmpty(value)) {
value = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", name);
}
Log.i(TAG, "Attribute name :" + name + " Attribute value:" + value );
}
最后的輸出結(jié)果是
09-02 14:48:26.455 I/NavigationBar(13763): Attribute name :layout_width Attribute value:-2
09-02 14:48:26.455 I/NavigationBar(13763): Attribute name :layout_height Attribute value:35.0dip
09-02 14:48:26.455 I/NavigationBar(13763): Attribute name :leftText Attribute value:back
09-02 14:48:26.455 I/NavigationBar(13763): Attribute name :leftImage Attribute value:@2130837580
前面3行都很正常,但是@2130837580是個(gè)什么鬼?
熟悉的童鞋一眼就能看出來(lái),這其實(shí)是一個(gè)引用ID值,如果要獲得引用的具體值還需要做額外的處理
if (name.equals("leftImage")) {
int id = attrs.getAttributeResourceValue("http://schemas.android.com/apk/res-auto", "leftImage", -1);
Drawable drawable = context.getResources().getDrawable(id);
Log.i(TAG, "drawable:" + drawable);
}
這里會(huì)打印出drawable對(duì)象.
如果使用TypedArray就可以很方便拿到具體的值,無(wú)論是引用還是硬編碼。
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.NaviBar);
Drawable leftDrawable = typedArray.getDrawable(R.styleable.NaviBar_leftImage);
所以,通過(guò)AttributeSet,不僅可以獲得android namespace的值,也能獲得自定義屬性的值,不過(guò)稍微有點(diǎn)麻煩,這也就是為什么一般都會(huì)使用TypedArray來(lái)
declare-styleable
其中flag和enum是相對(duì)來(lái)說(shuō)比較少用的標(biāo)簽,這里大致講下怎么使用
<declare-styleable name="NaviBar">
<attr name="flagTest">
<flag name="flag0" value="1" />
<flag name="flag1" value="2" />
</attr>
<attr name="enumTest">
<enum name="enum0" value="0" />
<enum name="enum1" value="1" />
</attr>
</declare-styleable>
配置自定義屬性
因?yàn)槭莈num類(lèi)型的,所以這里只能是單一的值
navibar:flagTest="flag0|flag1"
navibar:enumTest="enum0"
獲取值
int flagValue = typedArray.getInt(R.styleable.NaviBar_flagTest, -1);
int enumValue = typedArray.getInt(R.styleable.NaviBar_enumTest, -1);
Log.i(TAG, "Attribute flagValue :" + flagValue + " enumValue:" + enumValue);
會(huì)打印出如下log
09-02 16:22:25.715 I/NavigationBar(15186): Attribute flagValue :3 enumValue:0
可以看出flagValue的值就是flag0+flag1的值