Android中自定義樣式與View的構(gòu)造函數(shù)中的第三個(gè)參數(shù)defStyle的意義

Android中自定義樣式與View的構(gòu)造函數(shù)中的第三個(gè)參數(shù)defStyle的意義

零司忱、序

一、自定義Style

二屯远、在XML中為屬性聲明屬性值

1. 在layout中定義屬性

2. 設(shè)置Style

3. 通過(guò)Theme指定

三金麸、在運(yùn)行時(shí)獲取屬性值

1.?View的第三個(gè)構(gòu)造函數(shù)的第三個(gè)參數(shù)defStyle

2. obtailStyledAttributes

3. Example

四卓囚、結(jié)論與代碼下載

零套鹅、序

系統(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)吟孙。

一澜倦、自定義Style

通過(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中為相應(yīng)的屬性聲明屬性值

我們知道,在xml中為屬性賦值有幾種不同的方式

直接在layout中使用屬性

設(shè)置style并在style中設(shè)置屬性

Application和Activity可以指定theme派殷,可以在theme中指定在當(dāng)前Application或Activity中屬性的默認(rèn)值

下面就分別看一下這三種方式

1. 直接在layout中使用屬性

在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é)中可以看到内列。

三撵术、在運(yùn)行時(shí)獲取屬性值

在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撼嗓。

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中指定的值”的意思在下面的示代碼中可以看到怖糊。

實(shí)驗(yàn)驗(yàn)證

相關(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中直接定義

結(jié)論

從前面的說(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中直接指定屬性值

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末漱贱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子夭委,更是在濱河造成了極大的恐慌幅狮,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件株灸,死亡現(xiàn)場(chǎng)離奇詭異崇摄,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)慌烧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門配猫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人杏死,你說(shuō)我怎么就攤上這事。” “怎么了淑翼?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵腐巢,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我玄括,道長(zhǎng)冯丙,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任遭京,我火速辦了婚禮胃惜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘哪雕。我一直安慰自己船殉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布斯嚎。 她就那樣靜靜地躺著利虫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪堡僻。 梳的紋絲不亂的頭發(fā)上糠惫,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音钉疫,去河邊找鬼硼讽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛牲阁,可吹牛的內(nèi)容都是我干的固阁。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼咨油,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼您炉!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起役电,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤赚爵,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后法瑟,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體冀膝,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年霎挟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了窝剖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡酥夭,死狀恐怖赐纱,靈堂內(nèi)的尸體忽然破棺而出脊奋,到底是詐尸還是另有隱情,我是刑警寧澤疙描,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布诚隙,位于F島的核電站,受9級(jí)特大地震影響起胰,放射性物質(zhì)發(fā)生泄漏久又。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一效五、第九天 我趴在偏房一處隱蔽的房頂上張望地消。 院中可真熱鬧,春花似錦畏妖、人聲如沸脉执。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)适瓦。三九已至,卻和暖如春谱仪,著一層夾襖步出監(jiān)牢的瞬間玻熙,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工疯攒, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嗦随,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓敬尺,卻偏偏與公主長(zhǎng)得像枚尼,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子砂吞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容