Attr绍刮、Style和Theme詳解

schnauzer.jpg

前言

這三個(gè)概念貫穿Android框架的方方面面,是Android程序設(shè)計(jì)中很重要的一環(huán)挨摸,理解它們孩革,并能學(xué)以致用,不但可以讓你的代碼變得簡(jiǎn)潔明了得运,還可以讓你的應(yīng)用更加靈活膝蜈。但目前網(wǎng)上資料對(duì)這塊介紹的知識(shí)點(diǎn)往往比較散,不是很系統(tǒng)全面熔掺,在此特以自己開發(fā)經(jīng)驗(yàn)總結(jié)此文一篇饱搏,希望可以幫助初學(xué)者把這三個(gè)概念徹底搞明白,開發(fā)出高質(zhì)量的Android代碼置逻。

概念說(shuō)明

Attr:屬性推沸,風(fēng)格樣式的最小單元;

Style:風(fēng)格券坞,它是一系列Attr的集合用以定義一個(gè)View的樣式鬓催,比如height、width恨锚、padding等宇驾;

Theme:主題,它與Style作用一樣眠冈,不同于Style作用于個(gè)一個(gè)單獨(dú)View飞苇,而它是作用于Activity上或是整個(gè)應(yīng)用。

Attr的定義

我們先舉一個(gè)框架中的源碼例子蜗顽,用來(lái)介紹下Android中是如何定義一個(gè)Attr的布卡,比如以下創(chuàng)建一個(gè)簡(jiǎn)單的TextView布局

TextView

其中layout_width對(duì)應(yīng)到框架中的attr信息如下:

<declare-styleable name="ViewGroup_Layout">
    <attr name="layout_width" format="dimension">
        <enum name="fill_parent" value="-1" />
        <enum name="match_parent" value="-1" />
        <enum name="wrap_content" value="-2" />
    </attr>
    ...
</declare-styleable>

從上可以看到layout_width可以使用三個(gè)枚舉值,并且其中fill_parent和match_parent的value值都為-1雇盖。做過(guò)Android開發(fā)的童鞋肯定知道忿等,從2.2開始Android框架就推薦用match_parent代替fill_parent,而以上代碼正實(shí)現(xiàn)了兼容崔挖,因?yàn)樗鼈儗?duì)應(yīng)的值都為-1贸街。

以上的textStyle的屬性信息在源碼中如下:

<attr name="textStyle">
    <flag name="normal" value="0" />
    <flag name="bold" value="1" />
    <flag name="italic" value="2" />
</attr>

它也對(duì)應(yīng)了三個(gè)值,但這里卻使用了flag標(biāo)簽狸相。細(xì)心的童鞋可能已經(jīng)明白了flag與enum的差別薛匪,flag表示這幾個(gè)值可以做或運(yùn)算,比如上面的textStyle脓鹃,你可以疊加使用逸尖,如用bold|italic表示既加粗也變成斜體,而enum只能讓你選擇其中一個(gè)值。

看完上例后娇跟,我們來(lái)試著自己自定義一個(gè)自己的屬性岩齿,在values目錄下創(chuàng)建一個(gè)attrs.xml文件,在<resources>元素里面首先申明一個(gè)自己的<declare-styleable>表示一個(gè)屬性組苞俘,再在里面加上屬性就行盹沈。如下我們定義一個(gè)DogStyle的屬性組,其中有三個(gè)屬性一個(gè)是dogSex吃谣,一個(gè)是dogName乞封,dogName的格式我們?cè)O(shè)置為string,最后一個(gè)是dogColor基协,這樣一個(gè)屬于我們自己的屬性就定義成功了歌亲。

DogStyle

attr的format根據(jù)字面意思也挺容易理解的,這里我解釋下reference的用法澜驮。它用在一些可以設(shè)置引用值的情況陷揪,比如@drawable/myImage@color/myColor等杂穷。當(dāng)然format也可以進(jìn)行或運(yùn)算悍缠,一般我們定義color類型的屬性時(shí),也一般會(huì)把format寫成format="reference|color"耐量,這樣我們不但可以設(shè)置顏色值飞蚓,如#FFFFFF,還可以使用我們自己定義的狗圖片廊蜒,如@drawable/dog_pic趴拧。

TIPS:format即使用錯(cuò),只要你自定義的View中獲取對(duì)應(yīng)類型值也是可以的山叮,只是在布局中寫代碼時(shí)著榴,IDE就不會(huì)根據(jù)你定義的format給出相應(yīng)的提示了,所以最好在自定義View時(shí)還是仔細(xì)斟酌下類型屁倔。

Style的使用

如下我們?cè)?code>styles.xml中定義一個(gè)雪納瑞風(fēng)格

<style name="SchnauzerStyle">
    <item name="dogName">雪納瑞</item>
    <item name="dogColor">@drawable/schnauzer</item>
    <item name="dogSex">boy</item>
</style>

下面我們看下如何讓一個(gè)Style作用在一個(gè)View上的脑又。
首先我們自定義了一個(gè)View命名為DogView,然后創(chuàng)建一個(gè)布局文件中加入該DogView視圖锐借,并讓該View使用SchnauzerStyle風(fēng)格问麸。代碼如下:

<cn.hadcn.test.DogView
    style="@style/SchnauzerStyle"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"/>

移步到DogView的Java代碼中,我們可以通過(guò)theme的obtainStyledAttributes方法來(lái)獲得我們剛剛定義的幾個(gè)Attr屬性在Style中的內(nèi)容钞翔,如下我們舉一個(gè)獲得dogName的例子:

final Resources.Theme theme = context.getTheme();
TypedArray dogArray = theme.obtainStyledAttributes(attrs, R.styleable.DogStyle, defStyleAttr, defStyleRes);

String name = dogArray.getString(R.styleable.DogStyle_dogName);
Log.e("dog", "name = " + name);

dogArray.recycle();

以上obtainStyledAttributes有四個(gè)入?yún)⒀下簦皟蓚€(gè)比較容易理解,后兩個(gè)用作指定默認(rèn)的Style布轿,表示如果attrs中沒有你想獲得的屬性哮笆,但如果你指定了默認(rèn)Style俺亮,它會(huì)去從該默認(rèn)的Style里面找你想要的屬性。defStyleAttrdefStyleRes功能一樣疟呐,指定的資源形式不同,前者表示一個(gè)默認(rèn)的指向一個(gè)style風(fēng)格的attr屬性东且,而后者你可以直接傳入一個(gè)style風(fēng)格的id启具。注意以上定義的Style只能在這個(gè)DogView中被使用,如果你想在其他View使用珊泳,就需要再在需要使用的View中增加這個(gè)Style鲁冯。這就是先前我們說(shuō)的Style只能作用于一個(gè)View。

Theme的使用

Theme與Style使用同一個(gè)元素標(biāo)簽<style>色查,區(qū)別在于所包含的屬性不同薯演,并且使用的地方也不一樣。Theme你需要設(shè)置到AndroidManifest.xml<application>或者<activity>標(biāo)簽下秧了,設(shè)置后跨扮,被設(shè)置的Activity或整個(gè)應(yīng)用下所有的View都可以使用該<style>里面的屬性了。

比如在上例中验毡,我們直接把SchnauzerStyle設(shè)置到<activity>標(biāo)簽中衡创,并把布局文件中DogView元素的style="@style/SchnauzerStyle"欄位刪除,以此來(lái)測(cè)試下晶通,這個(gè)Activity下的所有View是不是可以直接使用theme中聲明的這些屬性璃氢。

<activity
    android:name=".MainActivity"
    android:theme="@style/SchnauzerStyle">
    ...

以上理論上是可行的,不過(guò)運(yùn)行后狮辽,程序卻出現(xiàn)奔潰一也,出現(xiàn)以下錯(cuò)誤提示:

java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.

有些同學(xué)一眼可能就看出,因?yàn)樵谶@里Activity或Application的需要很多屬性才能工作的喉脖,而此處我們只給它傳一個(gè)SchnauzerStyle椰苟,這當(dāng)然不行,所以我們需要對(duì)這個(gè)Style做下處理动看,讓SchnauzerStyle繼承一個(gè)系統(tǒng)主題尊剔,如下:

<style name="SchnauzerStyle" parent="Theme.AppCompat">
    <item name="dogName">雪納瑞</item>
    <item name="dogColor">@drawable/schnauzer</item>
    <item name="dogSex">boy</item>
</style>

這樣一個(gè)雪納瑞主題就誕生了,而在這個(gè)Activity下的所有View都可以用雪納瑞的信息了菱皆。Application中定義theme的原理一樣须误,這里就不多說(shuō)了。

TIPS:框架使用Attr的順序是:View中的Style會(huì)優(yōu)先于Activity中的Theme仇轻,Activity中的Theme會(huì)優(yōu)先于Application中的Theme京痢,所以說(shuō)你可以定義整個(gè)應(yīng)用的總體風(fēng)格,但局部風(fēng)格你也可以做出自己的調(diào)整篷店。

Attr的獲得方法

有些情況下祭椰,我們可能需要使用theme中的屬性值臭家,比如下面我們想讓一個(gè)TextView直接顯示dogName這個(gè)屬性的內(nèi)容,并且使用系統(tǒng)字體的顏色方淤,則可以如下做:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="?android:textColorSecondary"
    android:text="?attr/dogName"/>

獲得一個(gè)Attr的方法钉赁,不同于普通資源使用@符號(hào)獲得的方式,而是需要使用?符號(hào)來(lái)獲得屬性携茂,整體的表達(dá)方式如下:

?[*<package_name>*:][*<resource_type>*/]*<resource_name>*

如果是本應(yīng)用中的attr使用你踩,則可以省去<package_name>部分。

此處的textColor使用當(dāng)前主題的android:textColorSecondary屬性內(nèi)容讳苦。因?yàn)橘Y源工具知道此處是一個(gè)屬性带膜,所以省去了attr (完整寫法:?android:attr/textColorSecondary)。

總結(jié)

我剛開始學(xué)Android的時(shí)候鸳谜,也總對(duì)這三個(gè)概念很迷惑膝藕,不知道什么是屬性,什么是風(fēng)格咐扭,什么是主題芭挽,它們之間又有什么關(guān)系?它們?cè)贏ndroid框架中又充當(dāng)什么角色蝗肪?又如何自己去定義览绿?但隨著學(xué)習(xí)的深入,越發(fā)覺得這三塊內(nèi)容真是Android框架的一大神器穗慕,有時(shí)你不用改動(dòng)代碼饿敲,只要換一個(gè)theme,應(yīng)用馬上煥發(fā)青春逛绵。而且也嘗試用所學(xué)內(nèi)容去寫自己的theme怀各,不但可以讓自己的布局文件更加清晰明了,而且還讓自己的代碼具有更高的擴(kuò)展性术浪,真是好處多多瓢对,希望對(duì)這塊還不了解的童鞋多多研習(xí)。

作者簡(jiǎn)介
彭濤(@彭濤me) 致力于讓技術(shù)變得易懂且有趣
個(gè)人博客:http://pengtao.me, GitHub地址:https://github.com/CPPAlien

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末胰苏,一起剝皮案震驚了整個(gè)濱河市硕蛹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌硕并,老刑警劉巖法焰,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異倔毙,居然都是意外死亡埃仪,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門陕赃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)卵蛉,“玉大人颁股,你說(shuō)我怎么就攤上這事∩邓浚” “怎么了甘有?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)葡缰。 經(jīng)常有香客問(wèn)我梧疲,道長(zhǎng),這世上最難降的妖魔是什么运准? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮缭受,結(jié)果婚禮上胁澳,老公的妹妹穿的比我還像新娘。我一直安慰自己米者,他們只是感情好韭畸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蔓搞,像睡著了一般胰丁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上喂分,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天锦庸,我揣著相機(jī)與錄音,去河邊找鬼蒲祈。 笑死甘萧,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的梆掸。 我是一名探鬼主播扬卷,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼酸钦!你這毒婦竟也來(lái)了怪得?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤卑硫,失蹤者是張志新(化名)和其女友劉穎徒恋,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體欢伏,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡因谎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了颜懊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片财岔。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡风皿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出匠璧,到底是詐尸還是另有隱情桐款,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布夷恍,位于F島的核電站魔眨,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏酿雪。R本人自食惡果不足惜遏暴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望指黎。 院中可真熱鬧朋凉,春花似錦、人聲如沸醋安。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吓揪。三九已至亲怠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間柠辞,已是汗流浹背团秽。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叭首,地道東北人徙垫。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像放棒,于是被迫代替她去往敵國(guó)和親姻报。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,112評(píng)論 25 707
  • 關(guān)于Attr、Style和Theme詳解 本文主要參考以下三篇博客的內(nèi)容厢破,感謝三位的分享 1.Attr荣瑟、Style...
    ifjgm閱讀 5,974評(píng)論 2 17
  • 一笆焰、Attr 屬性,風(fēng)格樣式的最小單元见坑; Attr 的定義 在自定義 View 的時(shí)候嚷掠,在 res/attrs.x...
    秀花123閱讀 1,582評(píng)論 0 4
  • 自定義View分類 繼承自View通常用于實(shí)現(xiàn)一些不規(guī)則的效果捏检,這些效果不方便或者不能夠用布局組合的方式實(shí)現(xiàn)。這種...
    Cris_Ma閱讀 761評(píng)論 0 1
  • 伊人她伸出了手 纖纖如玉掃散眉間多愁 伊言她別無(wú)多求 但愿有人相守 黃昏直至夜曉 在黎明花于枝頭俏 為恨風(fēng)神不知花...
    瞳貓大人閱讀 212評(píng)論 0 1