Android 樣式系統(tǒng) | 主題背景屬性

在 Android 樣式系統(tǒng)系列的前幾篇文章中,我們介紹了主題背景與樣式的區(qū)別雪位,以及為什么說通過主題背景和公共主題背景屬性來分解您要實現(xiàn)的內(nèi)容是一個不錯的主意杂拨,請點擊鏈接回顧:

這會讓我們通過創(chuàng)建更少的布局或樣式,以隔離主題背景中的修改粘昨。在實際開發(fā)中壹哺,您通常希望根據(jù)主題背景改變顏色抄伍,因此您應(yīng)該始終通過主題背景屬性來引用顏色。

這意味著您可以將如下代碼視為有代碼異味 (Code smell):

<!-- Copyright 2019 Google LLC.  
   SPDX-License-Identifier: Apache-2.0 -->
<View …
  android:background="@color/white"/>

相反管宵,您應(yīng)該使用主題背景屬性截珍,它允許您按主題更改顏色,例如箩朴,在 深色主題 中提供一個不同的值:

<!-- Copyright 2019 Google LLC.
   SPDX-License-Identifier: Apache-2.0 -->
<View …
  android:background="?attr/colorSurface"/>

即使您當(dāng)前不支持其他主題 (什么岗喉,您的應(yīng)用還沒有支持深色主題?)炸庞,我們依然建議您采用這種方法钱床,因為這樣會讓新主題的采用變得更加簡單。

合格的 Colors 文件

您可以通過在不同的配置中添加不同的值來改變顏色 (例如埠居,在 res/values/colors.xml 中和在 res/values-night/colors.xml 中的備選值里均定義 @color/foo)查牌,但我們依然建議您使用主題背景屬性來替代它們事期。對顏色層級的區(qū)分,會迫使您給顏色賦予語義化名稱纸颜,換句話說刑赶,您應(yīng)該不會在給顏色命名為 @color/white 的同時,又為深色模式提供一個深色變體懂衩,這會讓人感到非常困惑。所以金踪,您可能會想要使用一個語義化名稱浊洞,例如 @color/background。這種方法帶來的問題是它合并了顏色聲明和具體的值胡岔,因此法希,它并沒有指出顏色是可以或者能夠隨主題背景而變化的。

@colors 的變化也會鼓勵您創(chuàng)造更多顏色靶瘸。如果在不同的情境下要使用具有相同值的苫亦、新的語義化命名的顏色 (即,不是背景色但應(yīng)該使用相同顏色)怨咪,這時候您仍需要在 colors 文件中創(chuàng)建新的條目屋剑。通過使用主題背景屬性,我們可以將語義顏色的聲明從提供它們的值中區(qū)分開來诗眨,而且讓使用方更清楚地了解到顏色會隨主題背景而變化 (因為它們使用 ?attr/ 語法)唉匾。將顏色聲明保持為字面值,您就可以自定義應(yīng)用使用的顏色調(diào)色板匠楚,并在主題背景級別修改它們巍膘,這會讓 color.xml 較小且易維護(hù)。

這種方法的額外好處是芋簿,布局/樣式引用這些顏色時復(fù)用性變得更高峡懈。由于主題背景可以被覆蓋或者改變,因此這間接表示: 您不需要創(chuàng)建其他布局或樣式就可以更改某些顏色——您可以在相同的布局中使用不同的主題背景与斤。

始終使用?

在某些情況下肪康,您或許不想按照主題背景更改顏色。例如幽告,在 Material Design 規(guī)范文檔 中提到梅鹦,您可能希望在淺色和深色主題中均使用同一類型的顏色。

在這種特殊情況下冗锁,直接引用顏色資源是再合適不過的:

<!-- Copyright 2019 Google LLC.  
   SPDX-License-Identifier: Apache-2.0 -->
<FloatingActionButton …
  app:backgroundTint="@color/owl_pink_500"/>

當(dāng)前發(fā)展?fàn)顩r

當(dāng)使用 ColorStateLists 時齐唆,您可能也不會在您的布局/樣式中直接引用主題背景屬性。

<!-- Copyright 2019 Google LLC.  
   SPDX-License-Identifier: Apache-2.0 -->
<View …
  android:background="@color/primary_20"/>

如果 primary_20 是一個 ColorStateList冻河,它本身引用主題背景屬性來獲取色值也可能是合理的 (請參見下文)箍邮。ColorStateLists 通常為不同的狀態(tài) (按下茉帅,禁用等) 提供不同的顏色,但它還有另外一種可用于主題化功能您可在選取的顏色上指定透明度值:

<!-- Copyright 2019 Google LLC.  
   SPDX-License-Identifier: Apache-2.0 -->
<selector …
  <item android:alpha="0.20" android:color="?attr/colorPrimary" />
</selector>

這種單項 ColorStateList (即只提供單個默認(rèn)顏色锭弊,而非每種狀態(tài)的不同顏色) 有助于減少您需要維護(hù)的顏色資源數(shù)量碾牌。它并沒有定義一個新的顏色資源的方式來手動為您 (每一個配置文件) 的 primary 顏色設(shè)置 alpha 值,而是通過改變當(dāng)前主題背景中的 colorPrimary 的方式本鸣。如果您的原始顏色發(fā)生了變化疙挺,則只需要在一個地方進(jìn)行更新,無需調(diào)整所有已更新的地方剑鞍。

雖然此技術(shù)很有用昨凡,但仍有一些注意事項:

  1. 如果指定的顏色也具有 alpha 值,則 alpha 會被合并蚁署。例如便脊,將 50% 的 alpha 應(yīng)用于 50% 的不透明白色中,將產(chǎn)生 25% 的白色:
<!-- Copyright 2019 Google LLC.  
   SPDX-License-Identifier: Apache-2.0 -->
<selector …
  <item android:alpha="0.50" android:color="#80ffffff" />
</selector>

因此光戈,最好將主題背景顏色指定為完全不透明哪痰,然后使用 ColorStateLists 修改它們的 alpha。

  1. 僅在 API 23 中添加了 alpha 組件久妆,因此晌杰,如果您的最小 sdk 低于這個版本,請確保使用支持此行為的 AppCompatResources.getColorStateList (并始終使用 android:alpha 命名空間筷弦,而絕不使用 app:alpha 命名空間)乎莉。

  2. 通常,我們使用簡寫法奸笤,將顏色設(shè)置為 Drawable惋啃,例如:

<!-- Copyright 2019 Google LLC.  
   SPDX-License-Identifier: Apache-2.0 -->
<View …
  android:background="@color/foo"/>

View 的背景是一個 Drawable,此簡寫把給定的顏色強(qiáng)轉(zhuǎn)成了一個 ColorDrawable监右。但是沒有辦法把 ColorStateList 轉(zhuǎn)換成 Drawable (API 29 之前使用 ColorStateListDrawable 解決這個問題)边灭。

但是,我們可以通過迂回的方式繞過此限制:

<!-- Copyright 2019 Google LLC.  
   SPDX-License-Identifier: Apache-2.0 -->
<View …
  android:background="@drawable/a_solid_white_rectangle_shape_drawable"
  app:backgroundTint="@color/some_color_state_list"/>

請確保您的 backgroundTint 支持您的 View 所需的狀態(tài)健盒,例如绒瘦,如果被禁用時需要更改。

強(qiáng)制執(zhí)行

即使您已經(jīng)說服自己使用主題背景屬性和 ColorStateList扣癣,但如何在代碼庫或者團(tuán)隊中使用呢惰帽?您可以在 Code review 期間嘗試保持警惕,但它的擴(kuò)展性不是很好父虑。更好的方法是依靠工具來解決此問題该酗。

《Making Android Lint Theme Aware》這篇文章簡述了如何通過添加 Lint 檢查來尋找直接引用顏色的用法,并涵蓋了文中提及到的所有建議。

間接使用

使用主題背景屬性和 ColorStateList 將顏色分解為主題背景的方法呜魄,可使您的布局和樣式更加靈活悔叽,提高代碼復(fù)用性并保持代碼庫的精簡和易維護(hù)性。

我們將在后續(xù)文章中介紹更多主題背景的用法以及它們之間的相互影響爵嗅,感興趣的讀者請繼續(xù)關(guān)注娇澎。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市睹晒,隨后出現(xiàn)的幾起案子趟庄,更是在濱河造成了極大的恐慌,老刑警劉巖伪很,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岔激,死亡現(xiàn)場離奇詭異,居然都是意外死亡是掰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門辱匿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來键痛,“玉大人,你說我怎么就攤上這事匾七⌒醵蹋” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵昨忆,是天一觀的道長丁频。 經(jīng)常有香客問我,道長邑贴,這世上最難降的妖魔是什么席里? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮拢驾,結(jié)果婚禮上奖磁,老公的妹妹穿的比我還像新娘。我一直安慰自己繁疤,他們只是感情好咖为,可當(dāng)我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著稠腊,像睡著了一般躁染。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上架忌,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天吞彤,我揣著相機(jī)與錄音,去河邊找鬼叹放。 笑死备畦,一個胖子當(dāng)著我的面吹牛低飒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播懂盐,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼褥赊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了莉恼?” 一聲冷哼從身側(cè)響起拌喉,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎俐银,沒想到半個月后尿背,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡捶惜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年田藐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吱七。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡汽久,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出踊餐,到底是詐尸還是另有隱情景醇,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布吝岭,位于F島的核電站三痰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏窜管。R本人自食惡果不足惜散劫,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望幕帆。 院中可真熱鬧舷丹,春花似錦、人聲如沸蜓肆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仗扬。三九已至症概,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間早芭,已是汗流浹背彼城。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人募壕。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓调炬,卻偏偏與公主長得像,于是被迫代替她去往敵國和親舱馅。 傳聞我的和親對象是個殘疾皇子缰泡,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,781評論 2 354