打造 Material 字體樣式主題 | 實現(xiàn)篇

使用 Material 主題 (Theming) 自定義 Material 組件,目的是讓組件觀感與品牌保持一致。Material 主題包括 顏色字體形狀 參數(shù),您可以對這些參數(shù)進行調整來獲得近乎無限的組件變體,同時保持其核心結構和易用性。

自版本 1.1.0 開始,您可以在 Android 中使用 Material 組件 (Material Design Components, MDC) 庫 來實現(xiàn) Material 主題。如果您要從設計支持庫 (Design Support Library) 或 MDC 1.0.0 遷移至新版 MDC,請參閱我們提供的遷移指南—— 遷移至 Android Material 組件

本文將重點討論如何實現(xiàn)字體樣式主題。

字體樣式屬性

Material Design 提供 13 種適用于應用中所有文字的 "樣式 (styles)",每一種樣式都有一個設計術語 (例如 "Body 1") 以及對應的字體樣式屬性,您可以在應用主題中覆寫這些屬性 (例如 textAppearanceBody1)。每一種樣式的屬性都有默認的 "基準" 值 (文字尺寸、字符間距、大小寫等)。

△ 具有基準值的 MDC 字體樣式屬性

Material 組件使用這些字體樣式屬性來為組件的文本元素設置樣式,這些組件通常繼承自 TextView 或組合了一個或多個 TextView。

△ 一個按鈕中使用的字體樣式屬性 (紅色)

字體樣式屬性在布局和組件樣式中的應用如下:

android:textAppearance=”?attr/textAppearanceBody1”

關于字體樣式屬性的使用,以及多種樣式化方案同時使用時被應用的優(yōu)先級順序,如需了解更多,請查閱 Nick Butcher 的文章 —— "如何實現(xiàn)文字外觀"。

在 MDC 主題中,這些屬性會映射到樣式上,例如:

<style name=”Theme.MaterialComponents.*” parent="...">
   ...
   <item name=”textAppearanceBody1”>
       @style/TextAppearance.MaterialComponents.Body1
   </item>
<style />

您也許在 AppCompat 或平臺中已經(jīng)接觸過 TextAppearance 樣式,我們將在本文的 字體樣式資源 部分進行詳細介紹。其對應的屬性是 MDC 的新增內容,使您能夠根據(jù)不同主題變換不同文字樣式。

選擇字體樣式

厘清應該選擇使用何種字體樣式以及其中的屬性值也許是設計師的責任,也許它們源自您的品牌。然而,了解每一種樣式的作用及其使用場景是非常有用的:

  • textAppearanceHeadline* 樣式應用于標題

  • textAppearanceSubtitle* 樣式應用于副標題

  • textAppearanceBody* 樣式應用于多行文本正文

  • textAppearanceButton 樣式應用于按鈕,但是同樣也適用于其他組件的部分內容,例如 Tab 和彈窗中的操作

  • textAppearanceCaption 樣式應用于小號文本,例如輸入框的提示和錯誤信息

  • textAppearanceOverline 樣式也應用于小號文本,但是它具有大寫英文字母和更大的字符間距,因此更適合于小標題和 Label,例如日期選擇器的標題

字體樣式工具

Material Design 提供了一個實用工具,它可以預覽字型縮放,集成了 Google Font,并且可以導出代碼。請查閱 Material Design 字體樣式指南 中的 "字型縮放生成器"。

![△ Google Font (左) 和字型縮放生成器 (右)](https://devrel.andfun.cn/devrel/posts/2021/08/SCcneI.png

字體樣式資源

字體樣式資源由字體和 TextAppearance 樣式組成。讓我們來看看 Android 中可用的資源以及聲明樣式時的注意事項。

XML 和可下載字體

字體存放于 res/font 目錄下,通過 @font/ 符號引用。您可以使用本地的 XML 字體 或者 可下載字體。Android Studio 內置了向導以幫助您開始使用可下載字體,包括配置必要的證書和清單元數(shù)據(jù)。請查閱由 Rod Sheeter 撰寫的 "助力 Android 開發(fā)者實現(xiàn)更好的排版指南" 來了解關于字體預加載更詳細的指南和進一步的優(yōu)化。

我們通常推薦使用可下載字體,因為它們會借助共享字體提供程序的緩存來減小應用包體積。但是,可下載字體目前僅可使用 Google Font 上的字體。如果您的應用需要使用已購買的字體或專用字體,請使用 XML 字體。

同樣值得注意的是,從 API 26 開始,Android 支持使用可變字體。請查閱 Rebecca Franks 的文章 —— "Android O 上的可變字體??" 以了解更多信息。

TextAppearance 樣式

TextAppearance 樣式可以被當成是 Android 上的 Material Design 字體樣式。對于自定義的樣式,我們推薦兩種方法來幫您實現(xiàn)關注點分離,并為應用中的字體樣式主題值創(chuàng)建單一的數(shù)據(jù)來源:

  • 將所有 TextAppearance 樣式存放在同一個 res/values/type.xml 文件中

  • 使用 MDC TextAppearance 作為父樣式,并遵守相同的命名規(guī)則

這些樣式中可使用的屬性和值與 TextView 支持的屬性和值一致:

  • fontFamily 定義字族,通常使用 @font/ 資源引用 XML 或可下載字體

  • android:textSize 定義文本的大小,通常是一個 sp 尺寸

  • android:textColor 定義文本的顏色

  • android:letterSpacing 定義字符的間距

  • android:textAllCaps 定義是否開啟文本大寫,是一個布爾值

  • android:textFontWeight 定義字體的粗細,用于從字族中選擇最接近的匹配項,但是只在 API 28 及以上的版本中可用。也可以使用 android:textStyle 來設置效果,例如 bold (粗體) 和 italic (斜體)

<!-- Copyright 2020 Google LLC.
   SPDX-License-Identifier: Apache-2.0 -->

<!-- In res/values/type.xml -->
<style name="TextAppearance.App.Headline6" parent="TextAppearance.MaterialComponents.Headline6">
    <item name="fontFamily">@font/roboto_mono</item>
    ...
</style>
<style name="TextAppearance.App.Body2" parent="TextAppearance.MaterialComponents.Body2">
    <item name="fontFamily">@font/roboto_mono</item>
    <item name="android:textSize">14sp</item>
    ...
</style>
<style name="TextAppearance.App.Button" parent="TextAppearance.MaterialComponents.Button">
    <item name="fontFamily">@font/roboto_mono</item>
    <item name="android:textAllCaps">false</item>
    ...
</style>

計算字符間距

字符間距在 Android 中使用的測量單位 (em) 與設計工具如 Sketch 使用的測量單位 (tracking) 不同。Material Design 排版指南 提供了一個相對簡單的方程式將 tracking 值轉換為合適的 em 值:

(Sketch 中的 tracking 值 / 字體尺寸 sp) = 字符間距

<!-- Copyright 2020 Google LLC.
   SPDX-License-Identifier: Apache-2.0 -->

<!-- (0.25 tracking / 14sp font size) = 0.0178571429 em -->
<style name="TextAppearance.App.Body2" parent="TextAppearance.MaterialComponents.Body2">
    <item name="fontFamily">@font/roboto_mono</item>
    <item name="android:textSize">14sp</item>
+    <item name="android:letterSpacing">0.0178571429</item>
    ...
</style>

MaterialTextView 和行高

系統(tǒng)版本的 TextView 在 API 28 中添加了 android:lineHeight 屬性。MDC 通過 MaterialTextView 類為該屬性提供了向下兼容能力。您不需要直接在布局中使用該類,因為 MaterialComponentsViewInflater 會自動將 <TextView> 替換為 MaterialTextView

您可以在多種場景中使用 lineHeight:

  • 作為一個 item 被包含于 TextAppearance 樣式中 (使用 android:textAppearance="..." 應用該樣式)
  • 作為一個 item 被包含于父樣式為 Widget.MaterialComponents.TextView 的組件樣式中 (使用 style="..." 應用該樣式)
  • 直接應用于布局中的 <TextView>
△ 不同的行高值

注意事項

  • 您不必覆寫全部字體樣式。但是請注意,默認的 MDC 樣式使用系統(tǒng)字體 (通常是 Roboto)。請確保檢查了您的組件和 TextView 使用的是哪種字體樣式。
  • 雖然 TextAppearance 支持設置 android:textColor,但 MDC 偏向于在主要組件樣式中聲明該屬性以保證遵循關注點分離原則,例如:
<style name=”Widget.MaterialComponents.*” parent=”...”>
   ...
   <!-- Color -->
   <item name=”android:textColor”>?attr/colorOnSurface</item>
   <!-- Type -->
   <item name=”android:textAppearance”>
       ?attr/textAppearanceBody1
   </item>
</style>

額外的字體樣式

如果您的設計系統(tǒng)需要的字體樣式在 Material 主題提供的 13 種樣式外,慶幸的是在 Android 中實現(xiàn)起來相對簡單,您可以通過如下方式聲明樣式屬性:

<!-- Copyright 2020 Google LLC.
   SPDX-License-Identifier: Apache-2.0 -->

<!-- In res/values/attrs.xml -->
<attr name="textAppearanceCustom" format="reference" />

<!-- In res/values/type.xml -->
<style name="TextAppearance.App.Custom" parent="TextAppearance.MaterialComponents.*">
    ...
</style>

<!-- In res/values/themes.xml -->
<style name="Theme.App" parent="Theme.MaterialComponents.*">
    ...
    <item name="textAppearanceCustom">@style/TextAppearance.App.Custom</item>
</style>

覆寫應用主題中的字體樣式

接下來,我們來討論如何通過覆寫相應屬性,將您選擇的字體樣式添加到應用主題中。

首先,我們建議您設置主題以便優(yōu)雅地處理淺色和深色調色板,同時也可以減少與基本主題的重復。如需了解更多此話題相關信息,請參閱 Chris Banes 撰寫的 深色主題文章,以及他和 Nick Butcher 的演講 —— "使用樣式開發(fā)主題"。

設置完成后,在您應用的基本主題中覆寫您想要改變的字體樣式屬性:

<!-- Copyright 2020 Google LLC.
   SPDX-License-Identifier: Apache-2.0 -->

<!-- In res/values/themes.xml -->
<style name="Theme.App.Base" parent="Theme.MaterialComponents.*">
    ...
    <item name="textAppearanceHeadline6">
        @style/TextAppearance.App.Headline6
    </item>
    <item name="textAppearanceBody2">
        @style/TextAppearance.App.Body2
    </item>
    <item name="textAppearanceButton">
        @style/TextAppearance.App.Button
    </item>
    <!-- Using default values for textAppearanceSubtitle1, textAppearanceCaption, etc. -->
</style>

Material 組件會響應主題級的字體樣式覆寫:

△ Material 組件響應主題級的字體樣式覆寫

MDC 組件中的字體樣式

您已經(jīng)知道 MDC 組件會響應主題級的樣式覆寫。但是您如何知道諸如某個按鈕使用 textAppearanceButton 作為它文本標簽的樣式呢?讓我們來看看以下幾種方式。

構建 Material 主題

構建 Material 主題 是一個可交互的 Android 項目,您可以通過它修改顏色、字體樣式、形狀的值來創(chuàng)建您自己的 Material 主題。它還包含了所有主題參數(shù)和組件的目錄。您可以按如下步驟來確定哪些組件會響應主題字體樣式屬性的改變:

△ 構建 Material 主題中的字體樣式變化

MDC 開發(fā)者文檔

MDC 開發(fā)者文檔已于最近更新。在本次更新中,我們加入了屬性表,涵蓋了開發(fā)庫中所使用的設計術語和屬性默認值。例如下面是更新的 按鈕文檔 的 "Anatomy and key properties" (詳解和關鍵屬性) 部分。

△ MDC 按鈕開發(fā)者文檔中屬性表包含了字體樣式的默認值

源碼

檢索 MDC 源碼可以說是最可靠的方式。MDC 使用默認樣式來實現(xiàn) Material 主題,因此可以查看這些樣式以及任何可樣式化屬性和 Java 文件。例如,查閱 MaterialButton 的 樣式屬性Java 文件

△ MDC 按鈕默認樣式中使用的字體樣式

自定義 View 中的字體樣式

您的應用中也許會引入您自己開發(fā)或現(xiàn)有庫中的自定義組件。當它們與標準 MDC 組件共同使用時,有必要保證它們能響應 Material 主題變化。以下是為自定義組件支持樣式主題化的注意事項。

在 <declare-styleable> 和默認樣式中使用 MDC 屬性

當自定義 View 使用了<declare-styleable> 標簽時將可被樣式化。復用 MDC 中的 attr name 有利于保持統(tǒng)一。使用 <declare-styleable> 標簽的默認樣式同樣可以引用 MDC 主題樣式的屬性作為它們的值。

<!-- Copyright 2020 Google LLC.
   SPDX-License-Identifier: Apache-2.0 -->

<!-- In res/values/attrs.xml -->
<declare-styleable name="AppCustomView">
    <attr name="titleTextAppearance" />
    <attr name="subtitleTextAppearance" />
    ...
</declare-styleable>

<!-- In res/values/styles.xml -->
<style name="Widget.App.CustomView" parent="android:Widget">
    <item name="titleTextAppearance">?attr/textAppearanceHeadline6</item>
    <item name="subtitleTextAppearance">?attr/textAppearanceBody2</item>
    ...
</style>

下一步

我們已經(jīng)在 Android 應用中實現(xiàn)了 MDC 字體樣式主題。有關 Material 主題的其他課題,請閱讀該系列其他文章。

我們一如既往地期待您在 GitHub 上提交 錯誤報告功能需求。另外請務必查看 Android 示例應用

歡迎您與我們 分享 您實現(xiàn)的字體樣式主題。如果您遇到任何問題,請 點擊這里 向我們提交反饋。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容