關(guān)于attr所需要知道的事

概述

在我們自定義view的時(shí)候,一般會(huì)用到自定義屬性,來(lái)做view的屬性配置(比如:顯示控制,dis/enable狀態(tài)等)。
自定義屬性的步驟如下

  1. 創(chuàng)建一個(gè)attr.xml,在styleable標(biāo)簽里自定義所需要的屬性
  2. 在布局xml文件中使用自定義view,配置自定義屬性的值
  3. 在自定義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的值

demo地址

github

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容