android AttributeSet API 之開發案例
在通過xml文件構造view組件的時候,往往都要使用到AttributeSet和defStyle這個兩個參數。
public class myButton extends Button{ public myButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar, defStyle, 0); } }
此時,
context會調用obtainStyledAttributes( AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)方法獲得一個TypedArray,然後根據這個TypeArray來設置組件的屬性。obtainStyledAttributes這類方法有好幾個,真正的實現是Resources.Theme類,分別是:
obtainStyledAttributes( AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) : TypedArray obtainStyledAttributes( int resid, int[] attrs) : TypeArray obtainStyledAttributes(int[] attrs) : TypeArray
在第一種方法裡根據attrs確定要獲取哪些屬性,然後依次通過其餘3個參數來取得相應的屬性值,屬性值獲取的優先級從高到低依次是set, defStyleAttr, defStyleRes. defStyleAttr是一個reference, 它指向當前Theme中的一個style, style其實就是各種屬性的集合,如果defStyleAttr為0或者在Theme中沒有找到相應的style, 則 才會嘗試從defStyleRes獲取屬性值,defStyleRes表示的是一個style的id, 當它為0時也無效。方法(2)和(3)分別表示從style或Theme裡獲取屬性值。
例如:
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar, defStyle, 0);
attr是在/res/values/attrs.xml文件下定義的,除瞭系統組件本身的屬性,我們也可以自定義屬性,然後在layout佈局中使用。attrs.xml裡通常包括若幹個attr集合,例如
就表示一個attr集合,declare-styleable標簽裡的name值表示的就是上面方法裡的attrs參數,android會自動在R文件中生成一個數組, 它可以使任意的不一定要是view組件名稱。在集合裡定義每個屬性的名稱和它的類型,據偶所見總共有reference, string, color, dimension, boolean等,如果允許多個類型可以用"|"來隔開,比如reference | color, attr還可以這樣定義
當attr的定義沒有指明format時,表示它已經在其他地方定義過瞭,所以你可以定義一個attr集合,裡面的都是已經定義好的屬性(例如系統組件的屬性), 然後通過obtainStyledAttributes方法來獲取這些屬性值,例如
當然,我們也需要聲明自己的命名空間
xmlns:app="https://schemas.android.com/apk/res/your_package_name"
R文件中會有styleable和attr這兩個類,當我們要使用哪個屬性集合或哪個屬性的時候用的是styleable, 而attr類定義的僅僅是attr這個屬性在layout中的id. AttributeSet有兩個方法分別是
int getAttributeNameResource(int index);
int getAttributeResourceValue(int index, int defaultValue);
前一個方法獲取的就是attr屬性名稱的id,也也就是attr類定義的數值,後一個方法獲取的才是attr屬性值。
例如,如果我們希望自定義ActionBar以適應不同的場景需要
public class MyActionBar extends LinearLayout { private CharSequence mTitle; private MyActionBar.Type mType; public enum Type { Normal, Dashboard, Dashboard } ublic MyActionBar(Context context, AttributeSet attrs, int defStyle) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar, defStyle, 0); mTitle = a.getString(R.styleable.ActionBar_title); int layoutID; int type = a.getInteger(R.styleable.ActionBar_type, -1); switch (type) { case 2: mType = Type.Empty; layoutID = R.layout.gd_action_bar_empty; break; case 1: mType = Type.Dashboard; layoutID = R.layout.gd_action_bar_dashboard; break; case 0: default: mType = Type.Normal; layoutID = R.layout.gd_action_bar_normal; break; } LayoutInflater.from(context).inflate(layoutID, this); a.recycle(); }
相應的在values/attrs.xml文件中