Android中自定義樣式與View的構(gòu)造函數(shù)中的第三個(gè)參數(shù)defStyle的意義
1.?View的第三個(gè)構(gòu)造函數(shù)的第三個(gè)參數(shù)defStyle
系統(tǒng)自帶的View可以在xml中配置屬性站蝠,對(duì)于寫(xiě)的好的Custom View同樣可以在xml中配置屬性肋坚,為了使自定義的View的屬性可以在xml中配置物独,需要以下4個(gè)步驟:
通過(guò)為自定義View添加屬性
在xml中為相應(yīng)的屬性聲明屬性值
在運(yùn)行時(shí)(一般為構(gòu)造函數(shù))獲取屬性值
將獲取到的屬性值應(yīng)用到View
怎么將獲取到的屬性值應(yīng)用到View就不用說(shuō)了,自己定義的屬性什么用處自己肯定是清楚的蝇棉,所以接下來(lái)看一下前三點(diǎn)吟孙。
通過(guò)元素聲明Custom View需要的屬性即可,下面是一個(gè)例子杰妓,文件是res/values/attrs.xml
在上述xml中藻治,我們聲明了Customize與CustomizeSyle,Customize包含了attr_one巷挥、attr_two桩卵、attr_three與attr_four四個(gè)attribute,CustomizeStyle也是一個(gè)attribute倍宾,但是卻沒(méi)有聲明在declare-styleable中雏节。
定義在declare-styleable中與直接用attr定義沒(méi)有實(shí)質(zhì)的不同,上述xml中高职,無(wú)論attr_one - attr_four是否聲明在declare-styleable中钩乍,系統(tǒng)都會(huì)為我們?cè)赗.attr中生成5個(gè)attribute
publicstaticfinalclassattr {publicstaticfinalintCustomizeStyle=0x7f010004;publicstaticfinalintattr_one=0x7f010000;publicstaticfinalintattr_two=0x7f010001;publicstaticfinalintattr_three=0x7f010002;publicstaticfinalintattr_four=0x7f010003;
}
不同的是,如果聲明在declare-styleable中初厚,系統(tǒng)還會(huì)為我們?cè)赗.styleable中生成相關(guān)的屬性件蚕。
publicstaticfinalclassstyleable {publicstaticfinalint[] Customize ={0x7f010000, 0x7f010001, 0x7f010002, 0x7f010003};publicstaticfinalintCustomize_attr_one = 0;publicstaticfinalintCustomize_attr_two = 1;publicstaticfinalintCustomize_attr_three = 2;publicstaticfinalintCustomize_attr_four = 3;
}
如上所示,R.styleable.Customize是一個(gè)int[]产禾,而里面的元素的值正好和R.attr.attr_one - R.attr.attr_four一一對(duì)應(yīng),而R.styleable.Customize_attr_one等4個(gè)值就是R.attr.attr_one-R.attr.attr_four在R.styleable.Customize數(shù)組中的索引牵啦。這個(gè)數(shù)組和索引在第三步運(yùn)行時(shí)獲得屬性值時(shí)會(huì)用到亚情,將attr分組聲明在declare-styleabe中的作用就是系統(tǒng)會(huì)自動(dòng)為我們生成這些東西,如果不聲明在declare-styleable中哈雏,我們完全可以在需要的時(shí)候自己構(gòu)建這個(gè)數(shù)組楞件,由于數(shù)組是自己構(gòu)建的,每個(gè)屬性的下標(biāo)索引也就很清楚了裳瘪,只是比較麻煩土浸。以上一家之言,不過(guò)從使用及實(shí)驗(yàn)難上看確實(shí)是這樣的彭羹。
我們知道,在xml中為屬性賦值有幾種不同的方式
Application和Activity可以指定theme派殷,可以在theme中指定在當(dāng)前Application或Activity中屬性的默認(rèn)值
下面就分別看一下這三種方式
在xml layout中使用自定義屬性和使用系統(tǒng)屬性差不多还最,不過(guò)屬性所屬的namespace不同墓阀,比如像下面這樣。
像layout_width等屬性屬于android的namespace拓轻,自定義的屬性屬于當(dāng)前程序的namespace斯撮,只需像聲明android的namespace一樣聲明當(dāng)前程序的namespace就好,只需要把上面紅色部分的android換成當(dāng)前程序的包名扶叉。應(yīng)用屬性的時(shí)候也需要注意屬性的namespace勿锅。
2. 設(shè)置style并在style中設(shè)置屬性
看上面xml中綠色的那一行,我們?yōu)镃ustomTextView聲明了一個(gè)style:ThroughStyle枣氧,這個(gè)Style很簡(jiǎn)單粱甫,只是指定了兩個(gè)屬性的值
attr one from styleattr two from style
注意,在style中我們聲明了attr_one的值作瞄,同時(shí)在xml中也直接向attr_one賦了值茶宵,最終用哪一個(gè)有個(gè)優(yōu)先級(jí)的問(wèn)題,后面在第三節(jié):在運(yùn)行時(shí)獲取屬性值中再說(shuō)宗挥,接下來(lái)看下第三種方式乌庶。
3.?theme中指定在當(dāng)前Application或Activity中屬性的默認(rèn)值
attr one from themeattr two from themeattr three from theme@style/CustomizeStyleInThemeattr one from theme referenceattr two from theme referenceattr three from theme reference
在上述xml中,我們?cè)贏ppTheme中為attr_one契耿、attr_two與attr_three指定了值瞒大,但是同時(shí)也為CustomizeStyle指定了一個(gè)reference,而在這個(gè)reference中為attr_one搪桂、attr_two與attr_three指定了值透敌,CustomizeStyle就是我們?cè)赼ttrs.xml中定義的一個(gè)屬性。在theme中為屬性設(shè)置值的方式有兩這種踢械,直接在theme中定義或通過(guò)另一個(gè)attribute引用一個(gè)style酗电,這兩種方式還是有區(qū)別的,在下面的獲取屬性值一節(jié)中可以看到内列。
在styles.xml中,我們同時(shí)定義一個(gè)DefaultCustomizeStyle的style话瞧,它的作用等下可以看到嫩与。
attr one from defalut style resattr two from defalut style resattr three from defalut style res
先看下CustomTextView的代碼
publicclassCustomTextViewextendsTextView {privatestaticfinalString TAG = CustomTextView.class.getSimpleName();publicCustomTextView(Context context) {super(context);
}publicCustomTextView(Context context, AttributeSet attrs) {this(context, attrs,R.attr.CustomizeStyle);? ? }publicCustomTextView(Context context, AttributeSet attrs,intdefStyle) {super(context, attrs, defStyle);
TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.Customize,defStyle,R.style.DefaultCustomizeStyle);? ? ? ? String one=a.getString(R.styleable.Customize_attr_one);
String two=a.getString(R.styleable.Customize_attr_two);
String three=a.getString(R.styleable.Customize_attr_three);
String four=a.getString(R.styleable.Customize_attr_four);
Log.i(TAG,"one:" +one);
Log.i(TAG,"two:" +two);
Log.i(TAG,"three:" +three);
Log.i(TAG,"four:" +four);
a.recycle();
}
}
主要代碼都在第三個(gè)函數(shù)中,這里也沒(méi)做什么交排,只是通過(guò)Context的obtainStyledAttributes獲得了前面定義的4個(gè)屬性的值并打印了出來(lái)划滋。
View的第三個(gè)構(gòu)造函數(shù)的第三個(gè)參數(shù)defStyle
如果在Code中實(shí)例化一個(gè)View會(huì)調(diào)用第一個(gè)構(gòu)造函數(shù),如果在xml中定義會(huì)調(diào)用第二個(gè)構(gòu)造函數(shù)埃篓,而第三個(gè)函數(shù)系統(tǒng)是不調(diào)用的处坪,要由View(我們自定義的或系統(tǒng)預(yù)定義的View,如此處的CustomTextView和Button)顯式調(diào)用,比如在這里我們?cè)诘诙€(gè)構(gòu)造函數(shù)中調(diào)用了第三個(gè)構(gòu)造函數(shù)稻薇,并將R.attr.CustomizeStyle傳給了第三個(gè)參數(shù)嫂冻。
第三個(gè)參數(shù)的意義就如同它的名字所說(shuō)的,是默認(rèn)的Style塞椎,只是這里沒(méi)有說(shuō)清楚桨仿,這里的默認(rèn)的Style是指它在當(dāng)前Application或Activity所用的Theme中的默認(rèn)Style,以系統(tǒng)中的Button為例說(shuō)明案狠。
publicButton(Context context) {this(context,null);
}publicButton(Context context, AttributeSet attrs) {this(context, attrs,com.android.internal.R.attr.buttonStyle);}publicButton(Context context, AttributeSet attrs,intdefStyle) {super(context, attrs, defStyle);
}
在Code中實(shí)例化View會(huì)調(diào)用第一個(gè)構(gòu)造函數(shù)服傍,在XML中定義會(huì)調(diào)用第二個(gè)構(gòu)造函數(shù),在Button的實(shí)現(xiàn)中都調(diào)用了第三個(gè)構(gòu)造函數(shù)骂铁,并且defStyle的值是com.android.internal.R.attr.buttonStyle吹零。buttonStyle是系統(tǒng)中定義的一個(gè)attribute,系統(tǒng)默認(rèn)有一個(gè)Theme拉庵,比如4.0中是Theme.Holo
...@android:style/Widget.DeviceDefault.Button....
上面是系統(tǒng)默認(rèn)的Theme灿椅,為buttonStyle指定了一個(gè)Style
@android:drawable/btn_default_holo_dark?android:attr/textAppearanceMedium@android:color/primary_text_holo_dark48dip64dip
這個(gè)Style定義了系統(tǒng)中Button的默認(rèn)屬性,如background等钞支。
從文檔中第三個(gè)構(gòu)造函數(shù)的說(shuō)明中也可以看到茫蛹,這個(gè)構(gòu)造函數(shù)的作用是View的子類提供這個(gè)類的基礎(chǔ)樣式
View(Contextcontext,AttributeSetattrs, int defStyleAttr)
Perform inflation from XML andapply a class-specific base style.
上面說(shuō)的都比較抽象,還是直接看實(shí)例代碼來(lái)的清楚明白烁挟,實(shí)驗(yàn)用的代碼上面全都貼完了婴洼,這里直接看結(jié)果,但在這之前要先看一個(gè)函數(shù):obtainStyledAtributes撼嗓。
我們要獲取的屬性值都是通過(guò)這個(gè)函數(shù)返回的TypedArray獲得的柬采,這是官方說(shuō)明:obtainStyledAttributes,以下是函數(shù)原型:
publicTypedArray obtainStyledAttributes (AttributeSet set,int[] attrs,intdefStyleAttr,intdefStyleRes)
4個(gè)參數(shù)的意思分別是:
set:屬性值的集合
attrs:我們要獲取的屬性的資源ID的一個(gè)數(shù)組且警,如同ContextProvider中請(qǐng)求數(shù)據(jù)庫(kù)時(shí)的Projection數(shù)組粉捻,就是從一堆屬性中我們希望查詢什么屬性的值
defStyleAttr:這個(gè)是當(dāng)前Theme中的一個(gè)attribute,是指向style的一個(gè)引用振湾,當(dāng)在layout xml中和style中都沒(méi)有為View指定屬性時(shí)杀迹,會(huì)從Theme中這個(gè)attribute指向的Style中查找相應(yīng)的屬性值,這就是defStyle的意思押搪,如果沒(méi)有指定屬性值,就用這個(gè)值浅碾,所以是默認(rèn)值大州,但這個(gè)attribute要在Theme中指定,且是指向一個(gè)Style的引用垂谢,如果這個(gè)參數(shù)傳入0表示不向Theme中搜索默認(rèn)值
defStyleRes:這個(gè)也是指向一個(gè)Style的資源ID厦画,但是僅在defStyleAttr為0或defStyleAttr不為0但Theme中沒(méi)有為defStyleAttr屬性賦值時(shí)起作用
鏈接中對(duì)這個(gè)函數(shù)說(shuō)明勉強(qiáng)過(guò)得去,這里簡(jiǎn)要概括一下。對(duì)于一個(gè)屬性可以在多個(gè)地方指定它的值根暑,如XML直接定義力试,style,Theme排嫌,而這些位置定義的值有一個(gè)優(yōu)先級(jí)畸裳,按優(yōu)先級(jí)從高到低依次是:
直接在XML中定義>style定義>由defStyleAttr和defStyleRes指定的默認(rèn)值>直接在Theme中指定的值
看這個(gè)關(guān)系式就比較明白了,defStyleAttr和defStyleRes在前面的參數(shù)說(shuō)明中已經(jīng)說(shuō)了淳地,“直接在Theme中指定的值”的意思在下面的示代碼中可以看到怖糊。
相關(guān)的代碼都前面都已經(jīng)貼上了,不過(guò)為了方便查看颇象,這里再把相關(guān)的XML一起貼一遍
main_activity.xmlattrs.xmlstyles.xmlattr one from themeattr two from themeattr three from theme@style/CustomizeStyleInThemeattr one from theme referenceattr two from theme referenceattr three from theme referenceattr one from styleattr two from styleattr one from defalut style resattr two from defalut style resattr three from defalut style res
在Code中是這樣獲取屬性的
publicCustomTextView(Context context, AttributeSet attrs) {this(context, attrs,R.attr.CustomizeStyle);}publicCustomTextView(Context context, AttributeSet attrs,intdefStyle) {super(context, attrs, defStyle);
TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.Customize,defStyle,R.style.DefaultCustomizeStyle);? ? ...}
CustomizeStyle是定義的一個(gè)attribute伍伤,DefaultCustomizeStyle是定義的一個(gè)style。
從代碼中可以看到遣钳,R.attr.CustomizeStyle就是前面提到的defStyleAttr扰魂,R.style.DefaultCustomizeStyle就是defStyleRes。
在Styles.xml中我們?yōu)锳pp定義了一個(gè)Theme:AppTheme蕴茴,在這個(gè)Theme中直接為attr_one劝评、attr_two、attr_three定義了屬性值荐开,這個(gè)就是前面關(guān)系式中說(shuō)的直接在Theme中指定的值付翁。
在AppTheme中同時(shí)定義了CustomizeStyle,引用了一個(gè)Style晃听,在CustomTextView的構(gòu)造函數(shù)中分別打印了attr_one百侧、attr_two、attr_three能扒、attr_four的值佣渴,所以下面我們就可以通過(guò)Log輸出驗(yàn)證一下前面的關(guān)系式,如果一個(gè)attribute在多個(gè)位置都定義了值初斑,究竟哪一個(gè)起作用辛润。
如上圖所示:
attr_one同時(shí)在xml、style见秤、defStyleAttr砂竖、defStyleRes與Theme中直接定義了值,但起作用的是在xml中的定義
attr_two同時(shí)在style鹃答、defStyleAttr乎澄、defStyleRes與Theme中直接定義了值,但起用的是在style中的定義
attr_three同時(shí)在defStyleAttr测摔、defStyleRes與Theme中直接定義了值置济,但起作用的是defStyleAttr
attr_four在defStyleRes中定義了解恰,但結(jié)果仍是0。
這可以說(shuō)明:
1. 直接在XML中定義>style定義>由defStyleAttr定義的值>defStyleRes指定的默認(rèn)值浙于、直接在Theme中指定的值
2. defStyleAttr(即defStyle)不為0且在當(dāng)前Theme中可以找到這個(gè)attribute的定義時(shí)护盈,defStyleRes不起作用,所以attr_four雖然在defStyleRes(DefaultCustomizeStyle)中定義了羞酗,但取到的值仍為null腐宋。
為了看一下defStyleRes的作用,1. 我們?cè)贏ppTheme中加上attr_four的定義整慎,2. 向obtainStyledAttributes的第三個(gè)參數(shù)傳入0脏款,或者移除AppTheme中CustomizeStyle的定義,結(jié)果是一樣的
attr one from themeattr two from themeattr three from themeattr four from theme
由于defStyleAttr為0裤园,或者defStyleAttr不為0但是我們沒(méi)有為這個(gè)屬性賦值撤师,所以defStyleRes起作用,當(dāng)一個(gè)屬性沒(méi)有在XML和Style中賦值時(shí)拧揽,系統(tǒng)會(huì)在defStyleRes(此處為DefaultCustomizeStyle)查找屬性的值剃盾。
我們看到attr_three的值來(lái)自defStyleRes,而attr_four的值來(lái)自Theme中的直接定義(DefaultCustomizeStyle定義了attr_one淤袜、atrr_two痒谴、attr_three)?,這就說(shuō)明
1. defStyleAtrtr即defStyle為0或Theme中沒(méi)有定義defStyle時(shí)defStyleRes才起作用
2. defStyleRes>在Theme中直接定義
從前面的說(shuō)明可以得到以下結(jié)論:
要為自定義View自定義屬性铡羡,可以通過(guò)declare-styleable聲明需要的屬性
為了在Theme設(shè)置View的默認(rèn)樣式积蔚,可以同時(shí)定義一個(gè)format為reference的屬性att_a,在定義Theme時(shí)為這個(gè)attribute指定一個(gè)Style烦周,并且在View的第二個(gè)構(gòu)造函數(shù)中將R.attr.attr_a作為第三個(gè)參數(shù)調(diào)用第三個(gè)構(gòu)造函數(shù)
可以定義一個(gè)Style作為Theme中沒(méi)有定義attr_a時(shí)View屬性的默認(rèn)值尽爆。
可以在Theme中直接為屬性賦值,但優(yōu)先級(jí)最低
當(dāng)defStyleAttr(即View的構(gòu)造函數(shù)的第三個(gè)參數(shù))不為0且在Theme中有為這個(gè)attr賦值時(shí)读慎,defStyleRes(通過(guò)obtainStyledAttributes的第四個(gè)參數(shù)指定)不起作用
屬性值定義的優(yōu)先級(jí):xml>style>Theme中的默認(rèn)Sytle>默認(rèn)Style(通過(guò)obtainStyledAttributes的第四個(gè)參數(shù)指定)>在Theme中直接指定屬性值