android 自定義控件 使用declare-styleable進行配置屬性(源碼角度)

轉自: http://blog.csdn.net/vipzjyno1/article/details/23696537


最近在模仿今日頭條,發現它的很多屬性都是通過自定義控件並設定相關的配置屬性進行配置,於是便查詢瞭解了下declare-styleable,下面我把自己的使用感受和如何使用進行說明下。

declare-styleable:declare-styleable是給自定義控件添加自定義屬性用的。

官方的相關內部控件的配置屬性文檔:http://developer.android.com/reference/android/R.styleable.html


如果不知道如何查看源碼:點擊這裏


起初,在自定義控件的時候,會要求構造3個方法中的一個或多個,好比我自定義的控件PersonView,

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public PersonView(Context context) {  
  2.         super(context);  
  3.         // TODO Auto-generated constructor stub  
  4.     }  
  5.   
  6.     public PersonView(Context context, AttributeSet attrs, int defStyle) {  
  7.         super(context, attrs, defStyle);  
  8.         // TODO Auto-generated constructor stub  
  9.     }  
  10.   
  11.     public PersonView(Context context, AttributeSet attrs) {  
  12.         super(context, attrs);  
  13. }  
其中的AttributeSet attrs一般都沒給它配置和使用,所以不知道這個東西到底怎麼用,後來查看源碼發現,這個配置在默認情況下使用的是系統自己的默認配置,一旦你直接設定了它的屬性,默認屬性就會被你的賦值所替代。

下面我們拿TextView的源碼看看AttributeSet是如何進行操作的。

初始化時候,在佈局文件中寫android:text="拉拉";



初始化TextView的時候,它的類中的屬性都會初始化;




接着往下看,你可以看到以下代碼:


[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. TypedArray a = theme.obtainStyledAttributes(  
  2.             attrs, com.android.internal.R.styleable.TextViewAppearance, defStyle, 0);  
  3. TypedArray appearance = null;  
  4. int ap = a.getResourceId(  
  5.         com.android.internal.R.styleable.TextViewAppearance_textAppearance, -1);  
  6. a.recycle();  
  7. if (ap != -1) {  
  8.     appearance = theme.obtainStyledAttributes(  
  9.             ap, com.android.internal.R.styleable.TextAppearance);  
這個就是系統在默認的資源文件R.styleable中去獲取相關的配置。

如果appearance不爲空,它就會去尋找獲取相關屬性,接着往下看。


此時的text = "";     就是準備輸出的字符串初始化。

之後它便會查找你佈局文件XML中是否設定給了它text屬性值


之前我們設定過android:text="拉拉";  所以它便會得到相關的賦值,之後調用

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-size:18px;"> setText(text, bufferType);  
  2.  if (hint != null) setHint(hint);  
  3. </span>  
輸出該字符串。當資源檢查賦值完畢後,調用a.recycle();釋放。
同理也可以發現,像hint,textcolor這類屬性都是這麼初始化賦值的。


思路:

自定義控件並且自定義屬性的情況下,你可以通過這樣去獲取判斷是否配置了相關的屬性,並進行賦值操作。


從源碼那邊我們大體知道了一個控件的屬性配置和初始化流程,下面就讓我們按照這個思路去自己學習下如何自定義配置。


下面我要寫一個繼承了TextView的PersonView類,給它設定屬性配置,之後實現屬性的顯示。

1.首先,先寫attrs.xml

在res-vlaues文件夾下創建資源文件attrs.xml或則自定義一個資源文件xx.xml,都可以。

之後在裏面配置declare-styleable ,name爲PersonAttr

[html] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <declare-styleable name="PersonAttr">  
  4.         <attr name="name" format="reference" />  
  5.         <attr name="sex" format="reference" />  
  6.         <attr name="age" format="integer" />  
  7.         <attr name="weight">  
  8.             <flag name="fat" value="2" />  
  9.             <flag name="mid" value="1" />  
  10.             <flag name="thin" value="0" />  
  11.         </attr>  
  12.         <attr name="adult" format="boolean" />  
  13.         <attr name="textSize" format="dimension" />  
  14.     </declare-styleable>  
  15. </resources>  

我這裏設置了姓名name,性別sex,年齡age,以及特徵屬性weight(fat,mid,thin內部的3個屬性及對應的屬性值),還有是否成年adult,和TextView的字體大小textView。

可能這裏有人會問,format是什麼,裏面的單詞代表的又是什麼意思。

format就是格式,裏面的就是這個屬性對應的格式,下面列出來大致的格式有:

1. reference:參考某一資源ID,以此類推

(1)屬性定義:

<declare-styleable name = "名稱">

<attr name = "background" format = "reference" />

</declare-styleable>

(2)屬性使用:

<ImageView

android:layout_width = "42dip"

android:layout_height = "42dip"

android:background = "@drawable/圖片ID"

/>

2. color:顏色值

<declare-styleable name = "名稱">

<attr name = "textColor" format = "color" />

</declare-styleable>

3. boolean:布爾值

<declare-styleable name = "名稱">

<attr name = "focusable" format = "boolean" />

</declare-styleable>

4. dimension:尺寸值。注意,這裏如果是dp那就會做像素轉換

<declare-styleable name = "名稱">

<attr name = "layout_width" format = "dimension" />

</declare-styleable>

5. float:浮點值。

6. integer:整型值。

7. string:字符串

8. fraction:百分數。

9. enum:枚舉值

10. flag:是自己定義的,類似於 android:gravity="top",就是裏面對應了自己的屬性值。

11. reference|color:顏色的資源文件。
12.reference|boolean:布爾值的資源文件

注意://由於reference是從資源文件中獲取:所以在XML文件中寫這個屬性的時候必須 personattr:name="@string/app_name"這種格式,否則會出錯


2.設置好屬性文件後,在使用的佈局中寫相關配置:

[html] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:personattr="http://schemas.android.com/apk/res/com.example.declare_styleable"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent" >  
  5.   
  6.     <com.example.declare_styleable.PersonView  
  7.         android:layout_width="wrap_content"  
  8.         android:layout_height="wrap_content"  
  9.         personattr:name="@string/person_name"   
  10.         personattr:weight ="fat"  
  11.         personattr:adult ="false"  
  12.         personattr:textSize="@dimen/text_size"/>  
  13.   
  14. </RelativeLayout>  

這裏要先應用這個attr:
[html] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. xmlns:personattr="http://schemas.android.com/apk/res/com.example.declare_styleable"  

對應結構是:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. xmlns:你自己定義的名稱="http://schemas.android.com/apk/res/你程序的package包名"    (我這是com.example.declare_styleable)  

包名是配置文件中   package="com.example.declare_styleable" 這樣格式的

之後在佈局中自定義的類中設相關屬性:

你自己定義的名稱:你設的屬性 ="屬性值";


3.最後在自定義控件的構造方法中獲取你配置的屬性值:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public class PersonView extends TextView {  
  2.     public PersonView(Context context) {  
  3.         super(context);  
  4.         // TODO Auto-generated constructor stub  
  5.     }  
  6.   
  7.     public PersonView(Context context, AttributeSet attrs, int defStyle) {  
  8.         super(context, attrs, defStyle);  
  9.         // TODO Auto-generated constructor stub  
  10.     }  
  11.   
  12.     public PersonView(Context context, AttributeSet attrs) {  
  13.         super(context, attrs);  
  14.         // TODO Auto-generated constructor stub  
  15.         TypedArray tArray = context.obtainStyledAttributes(attrs,R.styleable.PersonAttr);//獲取配置屬性  
  16.         String name = tArray.getString(R.styleable.PersonAttr_name);<span style="font-family: Arial, Helvetica, sans-serif;">//得到屬性name</span>  
  17.         int age = tArray.getInt(R.styleable.PersonAttr_age, 15);  
  18.         Boolean adult = tArray.getBoolean(R.styleable.PersonAttr_adult, false);  
  19.         String str_adult = getAdultStatus(adult);  
  20.         int weight = tArray.getInt(R.styleable.PersonAttr_weight, 1);// 默認是中等身材,屬性爲:1  
  21.         String str_weight = getWeightStatus(weight);//獲得肥胖屬性  
  22.         float textSize = tArray.getDimension(R.styleable.PersonAttr_textSize,R.dimen.default_text_size);// 如果你設置爲DP等單位,會做像素轉換  
  23.         tArray.recycle();//回收資源  
  24. //      setTextSize(textSize);//設置字體大小  
  25.         setText("姓名:" + name + "\n" + "年齡:" + age + "\n" + "是否成年:" + str_adult  
  26.                 + "\n" + "體形:" + str_weight);//給自定義的控件賦值  
  27.     }  
  28.       
  29.     /** 根據傳入的值判斷是否成年 */  
  30.     public String getAdultStatus(Boolean adult ){  
  31.         String str_adult = "未成年";  
  32.         if (adult) {  
  33.             str_adult = "成年";  
  34.         }  
  35.         return str_adult;  
  36.     }  
  37.       
  38.     /** 根據傳入的值判斷肥胖狀態 */  
  39.     public String getWeightStatus(int weight){  
  40.         String str_weight = "中等";  
  41.         switch (weight) {  
  42.         case 0:  
  43.             str_weight = "瘦";  
  44.             break;  
  45.         case 1:  
  46.             str_weight = "中等";  
  47.             break;  
  48.         case 2:  
  49.             str_weight = "肥胖";  
  50.             break;  
  51.         default:  
  52.             break;  
  53.         }  
  54.         return str_weight;  
  55.     }  
  56. }  
運行後就是:



這樣,以後我們就可以根據這個方法,去自定義控件並自定義配置屬性了,大大提高了自定義佈局的使用效率。


對應的源碼下載地址:下載地址


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章