菜鳥進階之深入理解android自定義屬性(AttributeSet,TypedArray)

醞釀了很久,終於可以寫篇關於android自定義屬性的文章了,本來這篇文章的名字沒有"菜鳥進階之"的,然後發現這裏的內容挺有難度,配得上這5個字了。

這裏牽扯幾個類比如AttributeSet、TypedArray,屬性,xml文件等,內容有一點多,所以最重要的是理解每個東西是什麼。

首先可以參考一文章:http://blog.csdn.net/ff313976/article/details/7949614,該文章展示了一個可以使用的自定義的屬性的情況,這只是很多自定義屬性中的一種情況而已,對於理解自定義屬性還不夠。

屬性

自定義屬性,首先要定義出來屬性我們在attrs.xml文件裏:

[html] view plain copy
 print?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <attr name="textSize0" format="dimension" />  
  4.     <declare-styleable name="button1">  
  5.         <attr name="textSize1" format="dimension" />  
  6.         <attr name="textSize2" format="dimension" />  
  7.     </declare-styleable>  
  8.     <declare-styleable name="button2">  
  9.         <attr name="textSize3" format="dimension" />  
  10.         <attr name="textSize4" format="dimension" />  
  11.     </declare-styleable>  
  12. </resources>  
然後我們要看到產生什麼效果:

在R.java文件裏:

[java] view plain copy
 print?
  1. public final class R {  
  2.     public static final class attr {  
  3.         public static final int textSize0=0x7f010000;  
  4.         public static final int textSize1=0x7f010001;  
  5.         public static final int textSize2=0x7f010002;  
  6.         public static final int textSize3=0x7f010003;  
  7.         public static final int textSize4=0x7f010004;  
  8.     }  
  9.     public static final class styleable {  
  10.         public static final int[] button1 = {  
  11.             0x7f0100010x7f010002  
  12.         };  
  13.         public static final int button1_textSize1 = 0;  
  14.         public static final int button1_textSize2 = 1;  
  15.         public static final int[] button2 = {  
  16.             0x7f0100030x7f010004  
  17.         };  
  18.         public static final int button2_textSize3 = 0;  
  19.         public static final int button2_textSize4 = 1;  
  20.     };  
  21. }  

我在這裏把不相關的內容去掉了,在這裏我們可以看到通過修改attrs.xml,R文件的改變是多了兩個類,分別是attr類和styleable類,這裏我們要注意的是區分出來這兩個類,他們是不同的,後面獲得TypedArray的時候他們的區別就會很明顯。在我理解,attr就是屬性唄,就想定義一個變量似的定義一個屬性。styleable就是樣式,就是屬性的集合,在R文件裏體現的很明顯,button1就是樣式,它包含兩個屬性的地址,就是0x7f010001和0x7f010002。還有一個值得注意的地方時button1_textSize1這個屬性,它的作用就是下標。後面我們在TypedArray裏取值的時候會用到。

AttributeSet

api的解釋:

[plain] view plain copy
 print?
  1. A collection of attributes, as found associated with a tag in an XML document. Often you will not want to use this interface directly, instead passing it to Resources.Theme.obtainStyledAttributes() which will take care of parsing the attributes for you. In particular, the Resources API will convert resource references (attribute values such as "@string/my_label" in the original XML) to the desired type for you; if you use AttributeSet directly then you will need to manually check for resource references (with getAttributeResourceValue(int, int)) and do the resource lookup yourself if needed. Direct use of AttributeSet also prevents the application of themes and styles when retrieving attribute values.   
這裏只是粘了一部分過來,可以自己查看,反正AttributeSet這個類就是代表xml裏一個節點下面的屬性的集合,這個類一般都是系統在生成有xml配置的組件時生成,我們一般不去生成該對象。我們可以通過該對象操作xml裏對應的屬性,但是官方不建議這麼使用,最直接的原因上面英文裏有提到,就是它只是xml裏屬性的一個集合,沒有做其他的處理,比如一個樣式,這個類只是知道這個樣式不能直接拿到樣式裏面的屬性,其他原因不詳。在這裏展示一個粘一個直接使用AttributeSet獲取屬性的demo。

layout.xml文件的一部分:

[html] view plain copy
 print?
  1. <com.example.drawableedittext.DrawableEditText  
  2.     android:id="@+id/text1"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="wrap_content"  
  5.     android:layout_centerHorizontal="true"  
  6.     hint="@string/hit"  
  7.     imgRes="@drawable/phonenumber_click"  
  8.     nullImgRes="@drawable/phonenumber" />  
java文件獲取屬性的一部分代碼:

[java] view plain copy
 print?
  1. // 設置文字大小  
  2.         int textSize = attrs.getAttributeResourceValue(null"textSize"0);  
  3.         if (textSize != 0) {  
  4.             mEditText.setTextSize(textSize);  
  5.         }  
至於該類其他的方法可自行查看api或者源碼。在這裏我們需要理解AttributeSet是什麼,然後在使用的時候一般都是把AttributeSet封裝成TypedArray進行使用。

TypedArray

我認爲這個類是學習自定義屬性最重要的,首先來看它是什麼:

[java] view plain copy
 print?
  1. Container for an array of values that were retrieved with Resources.Theme.obtainStyledAttributes(AttributeSet, int[], intint) or Resources.obtainAttributes. Be sure to call recycle when done with them. The indices used to retrieve values from this structure correspond to the positions of the attributes given to obtainStyledAttributes.  
它就是屬性的集合,我們獲取屬性一般就是這個類的.getxxx()方法。

重點是學習這個類的實例是怎麼來的?一般是由context.obtainStyledAttributes這個方法,有4個重載的方法。

我們來看

[java] view plain copy
 print?
  1. TypedArray android.content.Context.obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)  

這個方法就是從資源裏挑出一些屬性來,按照順序放到TypedArray裏,參數可以控制從哪裏挑選屬性,挑選哪些。

參數set:挑選屬性的出處是AttributeSet。

參數attrs:這是一個屬性的數組,只是哪些屬性被挑選出來,在之前看R文件的時候R.styleable.button1就是這樣的數組,我們可以自己new這樣的數組,再賦值。

參數defStyleAttr:挑選屬性的出處是defStyleAttr。

參數defStyleRes:挑選屬性的出處是defStyleRes。

[java] view plain copy
 print?
  1. 通過第2個參數指定獲取一些屬性,獲取到的是一個類似數組的結果,它的下標就像數組似的從0開始。在這裏我們可以聯想到之前在attrs.xml文件裏定義的declare-styleable節點,定義這個節點會在R文件產生一個屬性數組如button1,還會產生下標比如button1_textSize1 = 0,這樣我們可以用R文件裏的這兩個屬性來處理獲取屬性的這些操作。當然我們也可以new出來int的數組,下標自己寫上去。  

獲取TypedArray裏數據的檢索範圍:

1)從AttributeSet獲取。

PS:我在layout.xml裏一個組件後面設置text屬性,也在style設置text屬性。在界面裏使用的是在layout.xml設置的,但是用TypedArray獲取,獲取到的是在style裏設置的,有待研究。

[java] view plain copy
 print?
  1. TypedArray a = context.obtainStyledAttributes(set, new int[]{R.attr.textSize0,android.R.attr.text}, 00);  

2)從defStyleAttr獲取。

使用這個方式檢索屬性,個人感覺稍微有點難理解,剛開始學習Android-ViewPagerIndicator這個庫的時候,想修改那些tab的外觀,所以才需要去學習自定義屬性,該庫使用的就是使用這個參數。這個參數是一個int,就是R文件裏attr類裏的一個屬性,在R文件裏這樣:

[java] view plain copy
 print?
  1. public final class R {  
  2.     public static final class attr {  
  3.         public static final int reference1=0x7f010001;  
  4.     }  
  5. }  
屬性的名字隨便,在attrs.xml文件裏:

[html] view plain copy
 print?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <attr name="reference1" format="reference" />  
  4. </resources>  
要求這個定義的屬性是引用類型的。

什麼意思呢?就是說使用這個方式,需要:

a、定義一個屬性,該屬性是應用類型的。

b、在AndroidManifest.xml裏給activity或者application設置theme,在這個theme裏包含一個屬性,比如上面我們定義的reference1屬性。這樣這個theme裏的reference1就對應着一組屬性的集合。

c、在obtainStyledAttributes方法的第3個參數傳入R文件裏reference對應的值。

[java] view plain copy
 print?
  1. TypedArray a = context.obtainStyledAttributes(nullnew int[]{R.attr.textSize0,android.R.attr.text}, R.attr.reference1, 0);  

作用:在該activity所在的theme裏,查找R.attr.reference1屬性對應的屬性集合,在這個集合中檢索出第2個參數所包含的屬性,存放在返回值裏。

3)從defStyleRes獲取。

這個方式比較簡單。如:

[java] view plain copy
 print?
  1. TypedArray a = context.obtainStyledAttributes(nullnew int[]{R.attr.textSize0,android.R.attr.text}, 0, R.style.referecceres1);  
PS:這裏注意一下2)和3),他們一個是R.attr.,一個是R.style.,要分清他們是使用的不同方式獲得的可被檢索的屬性集合。

至於從TypedArray裏獲得屬性的值的一些方法,查看api就可以,沒什麼可研究的。

其他

1.關於xmlns。

在文章開始時推薦的那篇文章中就有關於添加一個xmlns的用法

[html] view plain copy
 print?
  1. xmlns:myapp="http://schemas.android.com/apk/res/com.example.testtypedarray"  

這就是個命名空間,比如我們用安卓原生的屬性的時候如果打錯了,就會報錯,這是因爲那個屬性下有哪些屬性都是被規定好的,就在這裏規定的

[html] view plain copy
 print?
  1. xmlns:android="http://schemas.android.com/apk/res/android"  
可以看到

[html] view plain copy
 print?
  1. mya="1234"  
這樣添加屬性是不出錯的,因爲它不被命名空間限制。出錯時因爲命名空間裏沒有你打錯的那個屬性。

設置這個只是在layout.xml裏可以添加我們自定義的屬性,和我們獲取基本沒關係。


補充:

1.關於TypedArray的獲取方式,參看下面的官方的api:

[java] view plain copy
 print?
  1. Return a StyledAttributes holding the attribute values in set that are listed in attrs. In addition, if the given AttributeSet specifies a style class (through the "style" attribute), that style will be applied on top of the base attributes it defines.   
  2.   
  3. Be sure to call StyledAttributes.recycle() when you are done with the array.   
  4.   
  5. When determining the final value of a particular attribute, there are four inputs that come into play:  
  6.   
  7. Any attribute values in the given AttributeSet.   
  8. The style resource specified in the AttributeSet (named "style").   
  9. The default style specified by defStyleAttr and defStyleRes   
  10. The base values in this theme.   
  11. Each of these inputs is considered in-order, with the first listed taking precedence over the following ones. In other words, if in the AttributeSet you have supplied <Button textColor="#ff000000">, then the button's text will always be black, regardless of what is specified in any of the styles.  
  12.   
  13. Parameters:  
  14. set The base set of attribute values. May be null.  
  15. attrs The desired attributes to be retrieved.  
  16. defStyleAttr An attribute in the current theme that contains a reference to a style resource that supplies defaults values for the StyledAttributes. Can be 0 to not look for defaults.  
  17. defStyleRes A resource identifier of a style resource that supplies default values for the StyledAttributes, used only if defStyleAttr is 0 or can not be found in the theme. Can be 0 to not look for defaults.  
  18. Returns:  
  19. Returns a TypedArray holding an array of the attribute values. Be sure to call TypedArray.recycle() when done with it.  
發佈了19 篇原創文章 · 獲贊 5 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章