屬性
自定義屬性,首先要定義出來屬性,我們新建一個attrs.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="textSize0" format="dimension" /> <declare-styleable name="button1"> <attr name="textSize1" format="dimension" /> <attr name="textSize2" format="dimension" /> </declare-styleable> <declare-styleable name="button2"> <attr name="textSize3" format="dimension" /> <attr name="textSize4" format="dimension" /> </declare-styleable> </resources>
然后我們要看到產生什么效果:
在R.java文件里
public final class R { public static final class attr { public static final int textSize0=0x7f010000; public static final int textSize1=0x7f010001; public static final int textSize2=0x7f010002; public static final int textSize3=0x7f010003; public static final int textSize4=0x7f010004; } public static final class styleable { public static final int[] button1 = { 0x7f010001, 0x7f010002 }; public static final int button1_textSize1 = 0; public static final int button1_textSize2 = 1; public static final int[] button2 = { 0x7f010003, 0x7f010004 }; public static final int button2_textSize3 = 0; public static final int button2_textSize4 = 1; }; }
我在這里把不相關的內容去掉了,在這里我們可以看到通過修改attrs.xml,R文件的改變是多了兩個類,分別是attr類和styleable類,這里我們要注意的是區分出來這兩個類,他們是不同的,后面獲得TypedArray的時候他們的區別就會很明顯。在我理解,attr就是屬性唄,就想定義一個變量似的定義一個屬性。styleable就是樣式,就是屬性的集合,在R文件里體現的很明顯,button1就是樣式,它包含兩個屬性的地址,就是0x7f010001和0x7f010002。還有一個值得注意的地方時button1_textSize1這個屬性,它的作用就是下標。后面我們在TypedArray里取值的時候會用到。
AttributeSet
api的解釋:
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里屬性的一個集合,沒有做其他的處理,比如一個樣式,這個類只是知道這個樣式不能直接拿到樣式里面的屬性,其他原因不詳,舉個例子:在XML文件中定義View如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <com.yongdaimi.costomview.CustomTextView android:text="China" android:clickable="false" style="@style/text_style" android:textColor="@android:color/black" /> </RelativeLayout>
然后在java代碼解析當前所定義的屬性值。比如:style屬性。
package com.yongdaimi.costomview; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.widget.TextView; public class CustomTextView extends TextView { public CustomTextView(Context context) { this(context,null); } public CustomTextView(Context context, AttributeSet attrs) { this(context,attrs,0); } public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); int attributeCount = attrs.getAttributeCount(); Log.i("test123", "當前屬性個數為:"+attributeCount); for (int i = 0; i < attributeCount; i++) { String attributeName = attrs.getAttributeName(i); Log.i("test123",String.format("當前屬性索引為:%d,索引名為:%s", i,attributeName)); if (attributeName.equals("style")) { String attributeValue = attrs.getAttributeValue(i); Log.i("test123", "當前屬性值為::"+attributeValue); } } } }
程序打印如下:
可以看到,通過此種形式,無法徹底讀取出當前屬性的值。
TypedArray
我認為這個類是學習自定義屬性最重要的,首先來看它是什么:
Container for an array of values that were retrieved with Resources.Theme.obtainStyledAttributes(AttributeSet, int[], int, int) 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個重載的方法。
我們來看
TypedArray android.content.Context.obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
下面分別說一下四個參數的意思:
set: XML文件中定義的View的屬性的集合。舉例:假設你在XML文件中定義了一個TextView並給其指定了6個屬性,那么這個set里面就有6個屬性。這個東西在自定義View的構造方法里面,由操作系統返回的。
attrs: 這個View自身的屬性集合,是一個int數組。舉例:假設你需要自定義View,並需要設置其屬性,那么就需要在attrs.xml文件為其指定一個styleable。同樣,在R文件中就會自動生成一個int[]數組,int[]數組中包含的就是styleable里面指定的屬性。
defStyleAttr: 這是當前Theme中的一個attribute,是指向style的一個引用。如果在layout.xml和style中都沒有為View指定屬性時,會從Theme中這個attribute指向的style查找相應的屬性值
參考鏈接:
1.菜鳥進階之深入理解android自定義屬性(AttributeSet,TypedArray)
2.Android中自定義樣式與View的構造函數中的第三個參數defStyle的意義