打造 Material 字体样式主题 | 实现篇
使用 Material 主题 (Theming) 自定义 Material 组件,目的是让组件观感与品牌保持一致。Material 主题包括颜色、字体和形状参数,您可以对这些参数进行调整来获得近乎无限的组件变体,同时保持其核心结构和易用性。
Material 主题
https://material.io/design/material-theming/overview.html#material-themingMaterial 组件
https://material.io/components颜色
https://material.io/design/color/字体
https://material.io/design/typography/形状
https://material.io/design/shape/
自版本 1.1.0 开始,您可以在 Android 中使用 Material 组件 (Material Design Components, MDC) 库来实现 Material 主题。如果您要从设计支持库 (Design Support Library) 或 MDC 1.0.0 迁移至新版 MDC,请参阅我们提供的迁移指南——迁移至 Android Material 组件:
https://medium.com/androiddevelopers/migrating-to-material-components-for-android-ec6757795351
Material 组件 (Material Design Components, MDC) 库 https://github.com/material-components/material-components-android
本文将重点讨论如何实现字体样式主题。
字体样式属性
Material Design 提供 13 种适用于应用中所有文字的 "样式 (styles)",每一种样式都有一个设计术语 (例如 "Body 1") 以及对应的字体样式属性,您可以在应用主题中覆写这些属性 (例如 textAppearanceBody1)。每一种样式的属性都有默认的 "基准" 值 (文字尺寸、字符间距、大小写等)。
△ 具有基准值的 MDC 字体样式属性
Material 组件使用这些字体样式属性来为组件的文本元素设置样式,这些组件通常继承自 TextView 或组合了一个或多个 TextView。
android:textAppearance=”?attr/textAppearanceBody1”
关于字体样式属性的使用,以及多种样式化方案同时使用时被应用的优先级顺序,如需了解更多,请查阅 Nick Butcher 的文章 —— "如何实现文字外观"。
Nick Butcher
https://medium.com/@crafty如何实现文字外观
https://medium.com/androiddevelopers/whats-your-text-s-appearance-f3a1729192d
在 MDC 主题中,这些属性会映射到样式上,例如:
<style name=”Theme.MaterialComponents.*” parent="...">
...
<item name=”textAppearanceBody1”>
@style/TextAppearance.MaterialComponents.Body1
</item>
<style />
您也许在 AppCompat 或平台中已经接触过 TextAppearance 样式,我们将在本文的字体样式资源部分进行详细介绍。其对应的属性是 MDC 的新增内容,使您能够根据不同主题变换不同文字样式。
选择字体样式
厘清应该选择使用何种字体样式以及其中的属性值也许是设计师的责任,也许它们源自您的品牌。然而,了解每一种样式的作用及其使用场景是非常有用的:
textAppearanceHeadline* 样式应用于标题 textAppearanceSubtitle* 样式应用于副标题 textAppearanceBody* 样式应用于多行文本正文 textAppearanceButton 样式应用于按钮,但是同样也适用于其他组件的部分内容,例如 Tab 和弹窗中的操作 textAppearanceCaption 样式应用于小号文本,例如输入框的提示和错误信息 textAppearanceOverline 样式也应用于小号文本,但是它具有大写英文字母和更大的字符间距,因此更适合于小标题和 Label,例如日期选择器的标题
字体样式工具
Material Design 提供了一个实用工具,它可以预览字型缩放,集成了 Google Font,并且可以导出代码。请查阅 Material Design 字体样式指南中的 "字型缩放生成器"。
△ Google Font (左) 和字型缩放生成器 (右)
Google Font
https://fonts.google.com/Material Design 字体样式指南
https://material.io/design/typography/the-type-system.html#type-scale
字体样式资源
字体样式资源由字体和 TextAppearance 样式组成。让我们来看看 Android 中可用的资源以及声明样式时的注意事项。
XML 和可下载字体
字体存放于 res/font 目录下,通过 @font/ 符号引用。您可以使用本地的 XML 字体或者可下载字体。Android Studio 内置了向导以帮助您开始使用可下载字体,包括配置必要的证书和清单元数据。请查阅由 Rod Sheeter 撰写的 "助力 Android 开发者实现更好的排版指南" 来了解关于字体预加载更详细的指南和进一步的优化。
XML 字体
https://developer.android.google.cn/guide/topics/ui/look-and-feel/fonts-in-xml可下载字体
https://developer.android.google.cn/guide/topics/ui/look-and-feel/downloadable-fonts助力 Android 开发者实现更好的排版指南
https://medium.com/google-design/the-android-developers-guide-to-better-typography-97e11bb0e261
我们通常推荐使用可下载字体,因为它们会借助共享字体提供程序的缓存来减小应用包体积。但是,可下载字体目前仅可使用 Google Font 上的字体。如果您的应用需要使用已购买的字体或专用字体,请使用 XML 字体。
同样值得注意的是,从 API 26 开始,Android 支持使用可变字体。请查阅 Rebecca Franks 的文章 —— "Android O 上的可变字体🖍" 以了解更多信息。
Android O 上的可变字体
https://medium.com/over-engineering/variable-fonts-in-android-p-c5c918275646
TextAppearance 样式
将所有 TextAppearance 样式存放在同一个 res/values/type.xml 文件中 使用 MDC TextAppearance 作为父样式,并遵守相同的命名规则
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>
计算字符间距
<!-- 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>
Material Design 排版指南
https://material.io/design/typography/the-type-system.html#type-scale
MaterialTextView 和行高
系统版本的 TextView 在 API 28 中添加了 android:lineHeight 属性。MDC 通过 MaterialTextView 类为该属性提供了向下兼容能力。您不需要直接在布局中使用该类,因为 MaterialComponentsViewInflater 会自动将 <TextView> 替换为 MaterialTextView。
android:lineHeight
https://developer.android.google.cn/reference/android/widget/TextView#attr_android:lineHeight
MaterialTextView
https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/textview/MaterialTextView.java
MaterialComponentsViewInflater
https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/theme/MaterialComponentsViewInflater.java
您可以在多种场景中使用 lineHeight:
作为一个 item 被包含于 TextAppearance 样式中 (使用 android:textAppearance="..." 应用该样式)
作为一个 item 被包含于父样式为 Widget.MaterialComponents.TextView 的组件样式中 (使用 style="..." 应用该样式)
直接应用于布局中的 <TextView>
△ 不同的行高值
注意事项
您不必覆写全部字体样式。但是请注意,默认的 MDC 样式使用系统字体 (通常是 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>
额外的字体样式
<!-- 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>
覆写应用主题中的字体样式
Chris Banes
https://chrisbanes.medium.com/
Nick Butcher
https://medium.com/@crafty
使用样式开发主题
https://chris.banes.dev/developing-themes-with-style-berlin/
<!-- 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>
MDC 组件中的字体样式
构建 Material 主题
构建 Material 主题是一个可交互的 Android 项目,您可以通过它修改颜色、字体样式、形状的值来创建您自己的 Material 主题。它还包含了所有主题参数和组件的目录。您可以按如下步骤来确定哪些组件会响应主题字体样式属性的改变:
克隆该项目并在 Android Studio 中运行它 调整 res/values/type.xml 和 res/values/themes.xml 文件中的值 重新运行应用并观察视觉变化
构建 Material 主题 https://material.io/resources/build-a-material-theme 该项目 https://github.com/material-components/material-components-android-examples/tree/develop/MaterialThemeBuilder res/values/type.xml https://github.com/material-components/material-components-android-examples/blob/develop/MaterialThemeBuilder/app/src/main/res/values/type.xml res/values/themes.xml https://github.com/material-components/material-components-android-examples/blob/develop/MaterialThemeBuilder/app/src/main/res/values/themes.xml
MDC 开发者文档
按钮文档 https://material.io/components/buttons/android#contained-button
源码
样式 https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/button/res/values/styles.xml 属性 https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/button/res/values/attrs.xml Java 文件 https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/button/MaterialButton.java
自定义 View 中的字体样式
在 <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>
下一步
我们已经在 Android 应用中实现了 MDC 字体样式主题。有关 Material 主题的其他课题,请阅读该系列其他文章。
推荐开发者使用 Material Design 组件 https://medium.com/androiddevelopers/we-recommend-material-design-components-81e6d165c2dd
错误报告 https://github.com/material-components/material-components-android/issues/new?assignees=&labels=bug&template=bug_report.md&title=%5BComponent+name%5D+Short+description+of+issue 功能需求 https://github.com/material-components/material-components-android/issues/new?assignees=&labels=feature+request&template=feature_request.md&title=%5BComponent+name%5D+Short+description+of+request 示例应用 https://github.com/material-components/material-components-android-examples
推荐阅读