1. 准备工作
Material Design 是 Google 打造的设计系统,旨在帮助开发者针对 Android 以及其他移动平台和网络平台打造优质的数字体验。它深受现实世界和现实物体的纹理(包括物体如何反射光和投射阴影)启发构建而成。它提供了一些准则,指导如何以具有可读性、吸引力和一致性的方式构建应用界面。
在此 Codelab 中,您将学习 Material 主题设置,获得自定义颜色、排版和形状方面的指导,以便在您的应用中使用 Material Design。您可以根据应用的需要进行自定义。您还将学习如何添加顶部应用栏,以显示应用的名称和图标。
前提条件
- 熟悉 Kotlin 语言,包括语法、函数和变量。
- 能够在 Compose 中构建布局,包括带内边距的行和列。
- 能够在 Compose 中创建简单列表。
学习内容
- 如何将 Material 主题设置应用于 Compose 应用。
- 如何为您的应用添加自定义字体。
- 如何为您的应用添加自定义调色板。
- 如何向应用中的元素添加自定义形状。
- 如何向应用中添加顶部应用栏。
构建内容
- 您将构建一个遵循 Material Design 最佳实践的精美应用。
所需条件
- 最新版本的 Android Studio。
- 用于下载起始代码和字体的互联网连接。
2. 观看配套代码演示视频(可选)
如果您想要观看某位课程教师完成此 Codelab 的过程,请播放以下视频。
建议将视频全屏展开(使用视频右下角的 图标),以便更清楚地查看 Android Studio 和相关代码。
这是可选步骤。您也可以跳过视频,立即开始按照此 Codelab 中的说明操作。
3. 应用概览
在此 Codelab 中,您将创建 Woof,该应用会显示狗狗列表,并使用 Material Design 打造出色的应用体验。
对于 Woof 应用,我们邀请了一位设计师帮助我们设计这款应用,其中包括选择应用的调色板、排版和形状。我们知道,并非所有开发者都可以接触到设计师,但在此 Codelab 中,我们将向您展示使用 Material 主题设置实现各种设计的可能性。通过此 Codelab,您可以了解到日后如何使用 Material 主题设置来改进应用的外观和风格。
下面是该设计师的设计规范,其中详细介绍了应用在浅色主题和深色主题下的视觉设计。
应用设计:
浅色主题 | 深色主题 |
调色板
以下是由设计师选择的浅色和深色主题的调色板。
浅色:
颜色 | 名称 | 十六进制颜色 | 槽 |
Grey50 | #F8F9FA | primary | |
Green50 | #E6F4EA | surface | |
Green100 | #CEEAD6 | background | |
Grey700 | #5F6368 | secondary | |
Grey900 | #202124 | onSurface | |
Grey900 | #202124 | onPrimary |
深色:
颜色 | 名称 | 十六进制颜色 | 槽 |
White | #FFFFFF | primary | |
Grey100 | #F1F3F4 | onSurface | |
Grey100 | #F1F3F4 | onPrimary | |
Cyan700 | #129EAF | surface | |
Cyan900 | #007B83 | background | |
Grey900 | #202124 | secondary |
排版
以下是设计师为此应用选择的字体。
标题 | 字体 | 字体粗细 | 尺寸 |
h1 | 正常 | 30sp | |
h2 | 粗体 | 20sp | |
h3 | 粗体 | 14sp | |
body1 | 正常 | 14sp |
主题文件
Theme.kt 会存储所有关于应用主题的信息,这些信息通过颜色、排版和形状进行定义。在此 Codelab 中,您只对此文件进行一次修改,但这是一个需要您了解的重要文件。该文件内是可组合项 WoofTheme()
,用于设置应用的颜色、排版和形状。
@Composable
fun WoofTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
val colors = if (darkTheme) {
DarkColorPalette
} else {
LightColorPalette
}
MaterialTheme(
colors = colors,
typography = Typography,
shapes = Shapes,
content = content
)
}
在 MainActivity.kt 中,添加了 WoofTheme()
来提供 Material 主题设置。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
WoofTheme {
WoofApp()
}
}
}
}
查看 DefaultPreview()
。此外,还会添加 WoofTheme()
,以提供您在 Preview 标签页中看到的 Material 主题设置。
@Preview
@Composable
fun DefaultPreview() {
WoofTheme(darkTheme = false) {
WoofApp()
}
}
4. 获取起始代码
- 进入为此项目提供的 GitHub 代码库页面。
- 点击 Code 按钮。系统随即会打开一个对话框。
- 在对话框中,点击 HTTPS 标签页,然后点击网址旁边的
以复制。您将会在 Android Studio 中使用此网址。
- 如果 Android Studio 未打开,请将其打开,然后在 Welcome to Android Studio 窗口中点击 Get from VCS。
- 如果 Android Studio 已经打开,请依次选择 File > New > Project from Version Control…。
- 在 Get from Version Control 窗口中,从 Version Control 菜单中选择 Git。
- 在 URL 文本框中,输入您从 GitHub 代码库页面复制的链接。
- 在 Directory 菜单中,选择要从 GitHub 代码库克隆源代码的目录。
- 点击 Clone。
- 等待 Android Studio 下载完毕,然后打开项目。
- 在 Android Studio 的导航菜单中,点击
‘Run app’,然后确保应用按预期构建。
- 在导航菜单中,依次点击 Git > Branches…。
- 在 Git Branches 对话框中的 Remote Branches 部分下,选择之前提供的分支名称,然后点击 Checkout。
- 如果您需要切换分支,请依次点击 Git > Branches,选择要切换到的分支,然后点击 Smart Checkout。
查看起始代码
- 在 Android Studio 中打开起始代码。
- 依次打开 com.example.woof > data > Dog.kt。其中包含用于代表狗狗的照片、名字、年龄和爱好的
Dog data class
。它还包含狗狗列表以及您将在应用中用作数据的信息。 - 依次打开 res > drawable。此文件包含此项目所需的所有图片资源,包括应用图标、狗狗图片和图标。
- 依次打开 res > values > strings.xml。此文件包含您在此应用中使用的字符串,包括应用名称、狗狗名字、说明等。
- 打开 MainActivity.kt。此文件包含创建简单的列表的代码,该列表用于显示小狗的照片、狗狗的名字以及狗狗的年龄。
WoofApp()
包含用于显示DogItems
的LazyColumn
。DogItem()
包含一个Row
,用于显示小狗的照片和相关信息。DogIcon()
显示小狗的照片。DogInformation()
包含狗狗的名字和年龄。
确保您的模拟器/设备采用浅色主题
在此 Codelab 中,您将使用浅色主题和深色主题,不过,此 Codelab 中的大部分主题都采用浅色主题。开始之前,请确保您的设备/模拟器使用的是浅色主题。
如需在浅色主题下查看您的应用,请在模拟器或实体设备上执行以下操作:
- 进入设备的设置应用。
- 搜索深色主题,然后点击进入该主题。
- 如果深色主题处于开启状态,请将其关闭。
运行起始代码以查看应用的起始状态;这是一个列表,其中会显示狗狗的照片、名字和年龄。它能正常运行,但外观不好看,所以我们会解决该问题。
5. 添加颜色
在 Woof 应用中,您首先要修改的就是调色板。
调色板是您的应用使用的颜色组合。不同的颜色组合会激发不同的心情,这会影响用户使用您的应用时的感受。由于我们就这个应用与设计师进行了合作,因此设计师为我们选择了调色板。不过,Material Design 网站提供了颜色系统指南,以便您详细了解调色板以及如何自行生成调色板。
之前您在 Android 应用中添加颜色时,使用了 Color.RED
或 Color.PINK
等元素。如果要添加更具体的颜色,如天蓝色或玉绿色,该怎么办?
在 Android 系统中,颜色用十六进制颜色值表示。十六进制颜色代码以井号 (#) 字符开头,后跟六个字母和/或数字(代表该颜色的红色、绿色和蓝色 [RGB] 分量)。前两个字母/数字表示红色,后面的两个表示绿色,最后两个表示蓝色。
颜色还可以包含 Alpha 值(字母和/或数字),用于表示颜色的透明度(#00 表示不透明度为 0% [完全透明],#FF 表示不透明度为 100% [完全不透明])。若添加 alpha 值,则该值为井号 (#) 字符后的十六进制颜色代码的前两个字符。如果未添加 alpha 值,系统会假定它是 #FF,即 100% 不透明(完全不透明)。
以下是一些十六进制颜色值的示例。
颜色 | 名称 | 十六进制颜色 |
黑色 | #000000 | |
绿色 | #72D98C | |
蓝色 | #4285F4 | |
White | #FFFFFF |
您当然不需要记住颜色的十六进制颜色代码。我们提供了用于选择颜色的工具,这些工具可为您生成数字。在此 Codelab 中,我们提供了颜色。
下面是我们在应用中使用的调色板。请注意,没有 alpha 值;这意味着颜色为 100% 不透明度。
浅色:
颜色 | 名称 | 十六进制颜色 | 槽 |
Grey50 | #F8F9FA | primary | |
Green50 | #E6F4EA | surface | |
Green100 | #CEEAD6 | background | |
Grey700 | #5F6368 | secondary | |
Grey900 | #202124 | onSurface | |
Grey900 | #202124 | onPrimary |
您可能想知道什么是槽以及它们是如何分配的。
- primary 颜色是应用在屏幕和组件中最常显示的颜色。
- secondary 颜色为应用提供了更多强调和区分的方式。
- surface 颜色会影响卡片、工作表和菜单等组件的 Surface。
- background 颜色显示在可滚动的内容后面。
- on 颜色元素显示在调色板中其他颜色的上层,主要应用于文本、图标和描边。在调色板中,我们有一个 onSurface 颜色(显示在 surface 颜色的上层)和一个 onPrimary 颜色(显示在主要颜色的上层)。
有了这些插槽可以实现统一的设计系统,相关组件的颜色也相似。
某些组件会自动映射到颜色槽。例如,Surface
可组合项会自动将 background 颜色映射到 surface 槽。这意味着,您无需为 Surface
可组合项明确分配 surface 颜色;当您在应用中设置颜色主题时,它会自动显示。除这 6 个颜色槽之外,颜色槽的数量还多。不过,也并非必须全部分配。未在应用主题中指定的所有颜色都将采用基准 Material 颜色主题(用于定义应用的默认主题)中定义的颜色。
关于颜色的理论已足够 - 现在可以向应用中添加这个漂亮的调色板了!
向主题添加调色板
- 打开 Color.kt 文件。此文件用于为应用的调色板添加颜色。已经添加了一些映射到默认调色板的颜色。在已包含的颜色下方添加 Woof 应用调色板所需的这些新颜色。
//Light Theme
val Grey50 = Color(0xFFF8F9FA)
val Grey900 = Color(0xFF202124)
val Grey700 = Color(0xFF5F6368)
val Green50 = Color(0xFFE6F4EA)
val Green100 = Color(0xFFCEEAD6)
- 打开 Theme.kt 文件,并将
LightColorPalette
替换为以下代码,将颜色添加到它们的槽中。
private val LightColorPalette = lightColors(
background = Green100,
surface = Green50,
onSurface = Grey900,
primary = Grey50,
onPrimary = Grey900,
secondary = Grey700
)
WoofTheme()
会检查 darkTheme
是否设置为 true,并将 MaterialTheme
object
中的 colors
设置为浅色调色板(如果设置为 false)或深色调色板(如果设置为 true)。
@Composable
fun WoofTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
val colors = if (darkTheme) {
DarkColorPalette
} else {
LightColorPalette
}
MaterialTheme(
colors = colors,
typography = Typography,
shapes = Shapes,
content = content
)
}
向应用添加颜色
现在,颜色已添加,可以在应用的不同区域中使用它们了。您将使用:
- 针对列表背景使用
background
颜色。 - 针对列表项的背景使用
surface
颜色,使其在列表的背景颜色中显得更醒目。 - 针对文本使用
onSurface
颜色,使其在列表项颜色下更清晰易读。
其余两种颜色将在此 Codelab 的后续内容中使用。
- 打开 MainActivity.kt。在
WoofApp()
中,向LazyColumn
添加背景修饰符,使列表的背景变为绿色。将背景颜色设为您在 Theme.kt 中设置为background
的颜色。您可以通过MaterialTheme.colors.background
访问设置为应用主题的background
颜色的颜色。 - 点击 Preview 标签页中的 Build & Refresh。
import androidx.compose.material.MaterialTheme
import androidx.compose.foundation.background
LazyColumn(modifier =
Modifier.background(MaterialTheme.colors.background))
太棒了!背景现在的颜色为 Green100
。
- 在
DogItem()
中,将background()
扩展添加到Row
并传入MaterialTheme.colors.surface
。这会将Row
的背景颜色设置为使用应用主题中指定的surface
颜色。
import androidx.compose.ui.unit.dp
Row(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.background(MaterialTheme.colors.surface)
)
在预览标签页中,您会看到列表项现在与应用背景的颜色不同,并且每个列表项更加明显。
- 在
DogInformation()
中,将color
添加到狗狗名字文本可组合项和狗狗年龄文本可组合项。此操作会更改这两个文本可组合项的字体颜色。使用onSurface
颜色。
Column {
Text(
text = stringResource(dog.name),
color = MaterialTheme.colors.onSurface,
modifier = Modifier.padding(top = smallPadding)
)
Text(
text = stringResource(R.string.years_old, dog.age.toString()),
color = MaterialTheme.colors.onSurface
)
}
- 构建和刷新应用。显示狗狗名字和年龄的文字与背景形成了更明显的对比,更易于阅读,但在浅色主题中并不那么明显。
浅色主题:
下图显示了文本与深色主题的背景对比度,我们将在下一部分中实现此效果:
没有文本颜色的深色主题 | 有文本颜色的深色主题 |
深色主题
在 Android 系统中,可以选择将设备切换为深色主题。深色主题使用更暗、更柔和的颜色,并且:
- 可以大幅减少耗电量(具体取决于设备的屏幕技术)。
- 为弱视以及对强光敏感的用户提高可视性。
- 让所有人都可以在光线较暗的环境中更轻松地使用设备。
您的应用可以选择启用 Force Dark,这意味着系统会为您实现深色主题。不过,如果您实现深色主题,可为用户提供更好的体验,以便您继续完全控制应用主题。
在选择自己的深色主题时,请务必注意,深色主题的颜色必须符合无障碍功能对比度标准。深色主题使用较深的界面颜色,且色彩强度有限。
以下是该应用的深色主题的颜色:
深色:
颜色 | 名称 | 十六进制颜色 | 槽 |
White | #FFFFFF | primary | |
Grey100 | #F1F3F4 | onSurface | |
Grey100 | #F1F3F4 | onPrimary | |
Cyan700 | #129EAF | surface | |
Cyan900 | #007B83 | background | |
Grey900 | #202124 | secondary |
添加深色主题
- 在 Color.kt 中,添加深色主题的颜色。请注意,您只能添加四种颜色,因为已经为浅色主题添加了
Grey900
。
//Dark Theme
val White = Color(0xFFFFFFFF)
val Grey100 = Color(0xFFF1F3F4)
val Cyan900 = Color(0xFF007B83)
val Cyan700 = Color(0xFF129EAF)
- 移除默认提供的颜色,因为我们不再需要这些颜色。现在,文件中应包含下列值。
//Light Theme
val Grey50 = Color(0xFFF8F9FA)
val Grey900 = Color(0xFF202124)
val Grey700 = Color(0xFF5F6368)
val Green50 = Color(0xFFE6F4EA)
val Green100 = Color(0xFFCEEAD6)
//Dark Theme
val White = Color(0xFFFFFFFF)
val Grey100 = Color(0xFFF1F3F4)
val Cyan900 = Color(0xFF007B83)
val Cyan700 = Color(0xFF129EAF)
- 在 Theme.kt 文件中,将现有的
DarkColorPalette
替换为下面显示的颜色。
private val DarkColorPalette = darkColors(
background = Cyan900,
surface = Cyan700,
onSurface = White,
primary = Grey900,
onPrimary = White,
secondary = Grey100
)
在预览中查看深色主题
如需查看深色主题的实际效果,您需要向 MainActivity.kt 添加另一个 Preview()
。这样,当您更改代码中的界面布局时,就能同时看到浅色主题和深色主题的预览效果。
- 在
DefaultPreview()
下,新建一个名为DarkThemePreview()
的函数,并为其添加@Preview
和@Composable
注解。
@Preview
@Composable
fun DarkThemePreview() {
}
- 在
DarkThemePreview()
内,添加WoofTheme()
。如果不添加WoofTheme()
,您将看不到我们在应用中添加的任何样式。将darkTheme
参数设置为 true。
@Preview
@Composable
fun DarkThemePreview() {
WoofTheme(darkTheme = true) {
}
}
- 在
WoofTheme()
内调用WoofApp()
。
@Preview
@Composable
fun DarkThemePreview() {
WoofTheme(darkTheme = true) {
WoofApp()
}
}
现在,当您点击 Preview
部分中的 Build & Refresh 并向下滚动时,会看到应用采用深色主题,包括颜色较深的应用/列表项背景和白色文字。您可以比较深色主题与浅色主题的区别。
深色主题 | 浅色主题 |
在设备或模拟器上查看深色主题
如需在模拟器或实体设备上以深色主题背景查看应用,请执行以下操作:
- 进入设备的设置应用。
- 搜索深色主题,然后点击进入该主题。
- 开启深色主题。
- 重新打开 Woof 应用后,该应用将采用深色主题。
此 Codelab 将重点介绍浅色主题,因此,请在继续设置此应用之前关闭深色主题。
- 进入设备的设置应用。
- 选择显示。
- 关闭深色主题。
比较应用在本部分开始时的外观与现在的外观。列表项和文本的定义更明确,配色方案更具视觉吸引力。
没有颜色 | 有颜色(浅色主题) | 有颜色(深色主题) |
6. 添加形状
默认情况下,应用中的所有形状都是矩形。不过,应用形状可能会给可组合项的外观和风格带来很大的变化。形状能够引导用户注意力、区别组件、传达状态以及表达品牌。
许多形状都是使用 RoundedCornerShape
定义的,后者描述的是圆角矩形。传入的数字定义角的圆度。如果使用 RoundedCornerShape(percent = 0)
,则矩形没有圆角;如果使用 RoundedCornerShape(percent = 50)
,角将变为完全圆形。如果您想尝试更复杂的形状,Material 网站可提供形状自定义工具。
百分之 0 | 百分之 25 | 百分之 50 |
Shape.kt 文件用于定义 Compose 中组件的形状。组件分为三种类型:小、中和大。在本部分中,您将修改定义为 medium
大小的 Card
组件。系统会根据组件的大小将组件分组为形状类别。
由于 Image
不是组件,因此您需要在 MainActivity.kt 中添加其形状。
在此部分中,您要将狗狗的图片设置为圆形,并修改列表项的形状。
将狗狗的图片的形状设为圆形
- 首先,您要将带狗狗照片的图标修改为圆形。打开 MainActivity.kt。在
DogIcon()
中,将clip
属性添加到Image
的modifier
;这会将图片裁剪为某种形状。传入RoundedCornerShape()
并传入 50,使角完全变为圆形。
import androidx.compose.ui.draw.clip
import androidx.compose.foundation.shape.RoundedCornerShape
@Composable
fun DogIcon(@DrawableRes dogIcon: Int, modifier: Modifier = Modifier) {
Image(
modifier = modifier
.size(64.dp)
.padding(8.dp)
.clip(RoundedCornerShape(50)),
查看 DefaultPreview
时,您会注意到狗狗图标已变为圆形!不过,有些照片的侧边会被截断,而不是显示为完整的圆形。
- 若要将所有照片设为圆形,请添加
ContentScale
和Crop
属性,这会剪裁图片。请注意,contentScale
是Image
的一个属性,不是modifier
的一部分。
import androidx.compose.ui.layout.ContentScale
@Composable
fun DogIcon(dogIcon: Int, modifier: Modifier = Modifier) {
Image(
modifier = modifier
.size(64.dp)
.padding(8.dp)
.clip(RoundedCornerShape(50)),
contentScale = ContentScale.Crop,
现在,当您运行应用时,图标会变成圆形。
向列表项添加形状
在此部分中,您将向列表项添加形状。列表项已显示在 Row
中,但 Row
无法完成形状设置。而应将 Row
添加到 Card
中。Card
是可以包含一个可组合项并包含装饰选项的 Surface。可通过边框、形状和高度等添加装饰。在本部分中,您将使用 Card
向列表项添加形状。
- 在
DogItem()
中,为Row
添加Card
。
import androidx.compose.material.Card
@Composable
fun DogItem(dog: Dog, modifier: Modifier = Modifier) {
Card() {
Row(
- 打开 Shape.kt 文件。
Card
是媒介组件,因此您将更新Shapes
对象的媒介属性。对于此应用,您想将列表的角设置为圆角,但不要使其完全成为圆形。为此,请将16.dp
传递给medium
属性。
val Shapes = Shapes(
small = RoundedCornerShape(4.dp),
medium = RoundedCornerShape(16.dp),
large = RoundedCornerShape(0.dp)
)
- 由于
Card
已默认使用中等形状,因此您无需将其显式设置为中型。刷新预览,您将看到圆角!但是,列表项之间没有内边距,并且不清楚一个列表项的结束位置以及下一个列表项的开始位置。现在,您将在列表项之间添加内边距,从而在列表项之间创建定义。
如果您返回到 WoofTheme()
中的 Theme.kt 文件并查看 MaterialTheme()
,会看到 shapes
属性设置为您刚刚更新的 Shapes
val
。
MaterialTheme(
colors = colors,
typography = Typography,
shapes = Shapes,
content = content
)
更新修饰符并添加内边距
- 由于
Card
现在是DogItem()
中显示的第一个可组合项,因此传递给DogItem
可组合项的修饰符应该转发到Card
,而不是转发到Row
。Row
现在使用Modifier
的新实例。
@Composable
fun DogItem(dog: Dog, modifier: Modifier = Modifier) {
Card(
modifier = modifier
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.background(MaterialTheme.colors.surface)
)
- 将
padding
添加到Card modifier
并传入8.dp
以在每个列表项周围添加内边距。
Card(
modifier = modifier.padding(8.dp)
)
现在,当您刷新预览时,由于列表项之间有内边距,所以您的列表项会更清晰地呈现出圆角。
不明确颜色
Card
是 Surface
,在 Theme.kt 文件中,我们为 surface
槽明确设置了颜色。因此,我们可以从 Row
中移除颜色,而无需明确将其设置为 surface
颜色。
- 在
DogItem()
中,移除背景颜色的明确设置。
Row(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
)
刷新预览,您会发现 Row
仍采用相同的背景颜色,尽管我们移除了明确的颜色分配。
- 由于狗的名字和年龄的
Text
位于Surface
之上,因此其颜色默认为onSurface
。移除DogInformation()
中的Text
项的明确颜色设置。
现在,该可组合项将如下所示:
@Composable
fun DogInformation(@StringRes dogName: Int, dogAge: Int, modifier: Modifier = Modifier) {
Column {
Text(
text = stringResource(dogName),
modifier = modifier.padding(top = 8.dp)
)
Text(
text = stringResource(R.string.years_old, dogAge)
)
}
}
为列表项添加高度
列表项的形状调整后,应用看起来非常漂亮,但我们要添加一些额外的设置,让列表项与背景形成更高的对比度。您已经使用 Card
shape
属性设置了列表项,现在您将使用 Card
elevation
属性为卡片添加高度。高度基本上是在 Card
与背景之间添加一种对比,即通过添加阴影来使应用看起来更真实且更有趣。
- 在
DogItem()
中,添加list_item_elevation
作为Card
的elevation
属性。
Card(
modifier = Modifier.padding(8.dp),
elevation = 4.dp
)
- 刷新预览。高度会增加应用的阴影和深度,使其看起来更逼真!
下图并排展示了该应用在调整形状前后的效果。请注意,如果添加形状,应用的外观会更具吸引力。
不调整形状 | 调整形状 |
7. 添加排版
Material Design 字体比例
字体缩放是一系列字体样式的选择,可在应用中使用,确保字体既灵活又一致。Material Design 字体比例包含字型系统支持的 13 种字体样式。只有在您想自定义应用时,才需要使用这些选项。如果您不知道为每个字体比例类别设置什么,请注意,您可以使用默认的排版缩放设置。
字体比例包含可重复使用的文本类别,每个类别都有预期的应用和含义。在我们的应用中,我们只会使用标题和正文类别。
标题
在字体比例中,标题的范围为 1 到 6。标题是屏幕上最大的文字,仅供重要文字或数字使用。
正文
正文文本的范围介于 1 到 2 之间,通常用于长篇幅撰写,因为它们适合较小的文本。
字体
Android 平台提供了一些字体,但您可能会想使用非默认提供的字体来对您的应用进行真正意义上的自定义。自定义字体可以增添个性,并可用于品牌塑造。
在本部分中,您将添加名为 Abril Fatface、Montserrat Bold 和 Montserrat Regular 的自定义字体。您将使用 H1 和 H2 标题以及 Material 字型系统中的 body1 文本,并将它们添加到应用中的文本中。
创建字体 Android 资源目录。
在向应用添加字体之前,您需要添加一个字体目录。
- 在 Android Studio 的项目视图中,右键点击 res 文件夹。
- 依次选择 New > Android Resource Directory。
- 将目录命名为 font,将资源类型设为 font,然后点击 OK。
- 打开位于 res > font 的新字体资源目录。
下载自定义字体
由于您使用的不是 Android 平台提供的字体,因此您需要下载自定义字体。
- 访问 https://fonts.google.com/。
- 搜索 Montserrat,然后点击 Download family。
- 解压缩该 ZIP 文件。
- 打开下载的 Montserrat 文件夹。在 static 文件夹中,找到 Montserrat-Bold.ttf 和 Montserrat-Regular.ttf(ttf 代表 TrueType 字体,即字体文件的格式)。选择两种字体,将它们拖动到 Android Studio 中项目的字体资源目录中。
- 在字体文件夹中将 Montserrat-Bold.ttf 重命名为 montserrat_bold.ttf,并将Montserrat-Regular.ttf 重命名为 montserrat_regular.ttf。
- 搜索 Abril Fatface,然后点击 Download family。
- 打开下载的 Abril_Fatface 文件夹。选择 AbrilFatface-Regular.ttf 并将其拖动到字体资源目录中。
- 在字体文件夹中,将 Abril_Fatface.ttf 重命名为 abril_fatface_regular.ttf。
项目中的字体资源目录和三个自定义字体文件应如下所示:
初始化字体
- 在项目窗口中,依次打开 ui.theme > Type.kt,然后删除
Typography
变量的内容。
// Set of Material typography styles to start with
val Typography = Typography(
)
- 在 import 语句下方和
Typography
val
上方初始化下载的字体。首先,初始化 Abril Fatface,方法是将其设为FontFamily
并使用字体文件abril_fatface_regular
传入Font
。
val AbrilFatface = FontFamily(
Font(R.font.abril_fatface_regular)
)
- 在 Abril Fatface 下方初始化 Montserrat,方法是将其设为
FontFamily
并使用字体文件montserrat_regular
传入Font
。对于montserrat_bold
,还应添加FontWeight.Bold
。即使您传入了字体文件的粗体版本,Compose 也不知道该文件是粗体文件,因此您需要明确地将此文件关联到FontWeight.Bold
。
val AbrilFatface = FontFamily(
Font(R.font.abril_fatface_regular)
)
val Montserrat = FontFamily(
Font(R.font.montserrat_regular),
Font(R.font.montserrat_bold, FontWeight.Bold)
)
接下来,将不同类型的标题设为您刚刚添加的字体。Typography
对象具有上面讨论的 13 种不同字体的参数。您可以根据需要定义任意数量。在此应用中,我们将设置 h1
(标题 1)、h2
(标题 2)和 body1
。在此应用的下一部分中,您将使用 h3
(标题 3),因此需在此处添加。
下表列出了应用概览部分中的表格,其中显示了您添加的每个标题的字体和字号。
标题 | 字体 | 字体粗细 | 尺寸 |
h1 | 正常 | 30sp | |
h2 | 粗体 | 20sp | |
h3 | 粗体 | 14sp | |
body1 | 正常 | 14sp |
- 使用上表填写
Typography
val
。对于h1
属性,应将其设置为TextStyle
,并使用上表中的信息填写fontFamily
、fontWeight
和fontSize
。这意味着所有设置为h1
的文本都将使用 Abril Fatface 作为字体,字体粗细正常,fontSize
为30.sp
。
对 h2
、h3
和 body1
重复此过程。
val Typography = Typography(
h1 = TextStyle(
fontFamily = AbrilFatface,
fontWeight = FontWeight.Normal,
fontSize = 30.sp
),
h2 = TextStyle(
fontFamily = Montserrat,
fontWeight = FontWeight.Bold,
fontSize = 20.sp
),
h3 = TextStyle(
fontFamily = Montserrat,
fontWeight = FontWeight.Bold,
fontSize = 14.sp
),
body1 = TextStyle(
fontFamily = Montserrat,
fontWeight = FontWeight.Normal,
fontSize = 14.sp
)
)
如果您返回到 WoofTheme()
中的 Theme.kt 文件并查看 MaterialTheme()
,会看到 typography
属性设置为您刚刚更新的 Typography
val
。
MaterialTheme(
colors = colors,
typography = Typography,
shapes = Shapes,
content = content
)
向应用文字添加排版
现在,您要为应用中的每一个文本实例添加标题类型。
- 添加
h2
(标题 2)作为dog name
的样式,因为它是一种简短的重要信息。将body1
添加为dog age
的样式,因为它适合较小的文本。
@Composable
fun DogInformation(@StringRes dogName: Int, dogAge: Int, modifier: Modifier = Modifier) {
Column {
Text(
text = stringResource(dogName),
style = MaterialTheme.typography.h2,
modifier = modifier.padding(top = 8.dp)
)
Text(
text = stringResource(R.string.years_old, dogAge),
style = MaterialTheme.typography.body1
)
}
}
- 刷新应用。现在,狗狗的名字会使用
20.sp
的粗体 Montserrat 字体显示,狗狗的年龄会使用14.sp
的正常 Montserrat 字体显示。
下图并排展示了该应用在添加排版前后的效果。请注意狗狗的名字和年龄之间的字体差异。
排版前 | 排版后 |
8. 添加顶部栏
Scaffold
是一种布局,可为各种组件和屏幕元素(如 Image
、Row
或 Column
)提供槽。Scaffold
还为 topBar
提供了槽,您将在本部分中使用。
topBar
可用于许多用途,但在本例中,您会将其用于品牌宣传以及彰显应用个性。您将创建一个类似于以下屏幕截图的可组合项,并将其放入 Scaffold
的 topBar
部分。
对于此应用,顶部栏由一个包含徽标和应用名称的行组成。徽标包含可爱的渐变色的爪子和应用名称!
向顶部栏添加图片和文字
- 在 MainActivity.kt 中,创建一个名为
WoofTopAppBar()
且接受modifier
的可组合项。
@Composable
fun WoofTopAppBar(modifier: Modifier = Modifier) {
}
- 在
WoofTopAppBar()
中,添加Row()
。
@Composable
fun WoofTopAppBar(modifier: Modifier = Modifier) {
Row() {
}
}
- 将
Image
添加到Row
中。使用painter
将Image
设置为可绘制对象文件夹中的ic_woof_logo
,并将contentDescription
设置为 null。在这种情况下,应用徽标不会为有视觉障碍的用户添加任何语义信息,因此我们无需添加内容说明。
Image(
painter = painterResource(R.drawable.ic_woof_logo),
contentDescription = null
)
- 接下来,在
Row
中的Image
后添加一个Text
可组合项,并使用stringResource()
将其设为app_name
的值。这会将文本设置为存储在strings.xml
中的应用的名称。
Text(
text = stringResource(R.string.app_name)
)
- 现在,您已将图标和应用名称添加到
TopAppBar()
,接下来需要将TopAppBar()
添加到布局中。在WoofApp()
中,添加围绕LazyColumn
的Scaffold
。
import androidx.compose.material.Scaffold
@Composable
fun WoofApp() {
Scaffold(
) {
LazyColumn(modifier =
Modifier.background(MaterialTheme.colors.background)) {
items(dogs) {
DogItem(dog = it)
}
}
}
}
- 在
Scaffold
中,添加topBar
属性并将其设置为WoofTopAppBar()
。
Scaffold(
topBar = {
WoofTopAppBar()
}
)
WoofApp()
可组合项将如下所示:
@Composable
fun WoofApp() {
Scaffold(
topBar = {
WoofTopAppBar()
}
) {
LazyColumn(modifier = Modifier.background(MaterialTheme.colors.background)) {
items(dogs) {
DogItem(dog = it)
}
}
}
}
- 刷新预览,然后查看顶部应用栏。它显示的是图标和文字,但看起来不像我们预期的成品。在下一部分中,您将使用颜色、排版和内边距等进行美化。
美化顶部栏
- 首先,我们要在顶部栏中添加一种背景颜色,以便与应用的其他部分区分开来。在
WoofTopAppBar()
中,通过向Row
添加modifier
并将背景颜色设置为primary
,添加主应用主题颜色作为背景颜色。
Row(
modifier = modifier
.background(color = MaterialTheme.colors.primary)
){ }
- 背景颜色仅出现在图标和文本后面,但您希望它覆盖应用的整个宽度。为此,请将
Row
上的modifier
设置为fillMaxWidth()
。
Row(
modifier = modifier
.fillMaxWidth()
.background(color = MaterialTheme.colors.primary)
){ }
- 接下来,更新文本以遵循您之前定义的
h1
(标题 1)样式。由于背景设置为primary
颜色,因此文本会自动设置为onPrimary
颜色。
Text(
text = stringResource(R.string.app_name),
style = MaterialTheme.typography.h1
)
- 效果看起来好多了,不过图片太小,可以在其周围使用一些内边距。为
Image
添加修饰符,并将图片尺寸设置为64.dp
,并将图片周围的内边距设置为8.dp
。
Image(
modifier = Modifier
.size(64.dp)
.padding(8.dp),
painter = painterResource(R.drawable.ic_woof_logo),
contentDescription = null
)
- 就快完成了!现在,将垂直对齐方式设置为
Alignment.CenterVertically
,这样可以垂直居中行中所有项。
import androidx.compose.ui.Alignment
Row(
modifier = modifier
.fillMaxWidth()
.background(color = MaterialTheme.colors.primary),
verticalAlignment = Alignment.CenterVertically
){ }
运行应用,欣赏 TopAppBar
将该应用关联在一起是多么美观。
不含顶部应用栏 | 带有顶部应用栏 |
现在,在深色主题下运行您的应用。由于栏使用 primary
颜色,而文本使用 onSurface
颜色,因此您无需为深色主题更新任何内容。
恭喜,您已完成了此 Codelab 的学习!
9. [可选] 更改状态栏
为了进一步提升用户体验,您可以更新状态栏的颜色,其中包含时间、互联网连接、电池状态等信息。
- 依次进入 app > res > values > colors.xml。
- 删除
<resources>
标记的内容。
<resources>
</resources>
- 添加
grey_50
,将其设置为浅色主题状态栏的#FFF8F9FA
,然后添加grey_900
并将其设置为深色主题状态栏的#FF202124
。
<resources>
<color name="grey_50">#FFF8F9FA</color>
<color name="grey_900">#FF202124</color>
</resources>
- 依次进入 app > res > values > themes.xml,并将
android:statusBarColor
中的颜色替换为grey_50
。
<resources>
<style name="Theme.Woof" parent="android:Theme.Material.Light.NoActionBar">
<item name="android:statusBarColor">@color/grey_50</item>
</style>
</resources>
- 在设备或模拟器上运行应用。
状态栏现在与顶部应用栏匹配,这使得配色方案看起来更统一,但现在很难看到图标。
- 在 themes.xml 文件中,在
statusBarColor
下添加windowLightStatusBar
并将其设为 true。
<resources>
<style name="Theme.Woof" parent="android:Theme.Material.Light.NoActionBar">
<item name="android:statusBarColor">@color/grey_50</item>
<item name="android:windowLightStatusBar">true</item>
</style>
</resources>
- 您会收到错误消息。将光标悬停在消息上,然后按 Override Resources in values-v23。
- 这将创建一个名为 v23/themes.xml 的新 themes.xml 文件,此文件用于 API 级别 23 及更高级别。
- 在模拟器上运行应用。请注意,您现在可以看到这些图标了!
在深色主题中添加状态栏
现在,您可以自定义深色主题的状态栏。
- 在 res 文件夹中,添加一个名为 values-night 的新 Android 资源目录。
- 切换到 Project Source Files 文件视图。
- 依次进入 app > src > main > res > values-night。
- 在 values-night 中,添加一个名为
themes.xml
的 Values Resource File。 - 添加名称为
Theme.Woof
且父元素为android:style/Theme.Material.NoActionBar
的样式标记。
<resources>
<style name="Theme.Woof" parent="android:style/Theme.Material.NoActionBar">
</style>
</resources>
- 将状态栏颜色添加为
grey_900
。由于默认图标为白色图标,因此您无需添加windowsStatusLightBar
。
<resources>
<style name="Theme.Woof" parent="android:style/Theme.Material.NoActionBar">
<item name="android:statusBarColor">@color/grey_900</item>
</style>
</resources>
- 使用深色主题运行应用,即可查看状态栏的更新。
10. 获取解决方案代码
如需下载完成后的 Codelab 代码,您可以使用以下 Git 命令:
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-woof.git $ cd basic-android-kotlin-compose-training-woof $ git checkout material
或者,您也可以下载 ZIP 文件形式的代码库,将其解压缩并在 Android Studio 中打开。
如果您想查看解决方案代码,请前往 GitHub 查看。
11. 总结
您刚刚创建了您的第一个 Material 应用!您为浅色和深色主题添加了自定义调色板,为不同的组件创建了形状,并下载了字体并将其添加到应用中,还创建了美观的顶部栏将它们统一在一起。运用您在此 Codelab 中学到的技能,并更改颜色、形状和排版,打造完全属于您自己的应用!
总结
- 借助 Material 主题设置,您可以依据关于自定义颜色、排版和形状的指南,在应用中使用 Material Design。
- 主题是在 Theme.kt 文件中通过名为 [您的应用名称]+Theme() 的可组合项定义的(在此应用中是
WoofTheme()
)。在该函数内,MaterialTheme
object
用于设置应用的color
、typography
、shapes
和content
。 - 您可以在 Colors.kt 中列出您在应用中使用的颜色。然后,在 Theme.kt 中,将
LightColorPalette
和DarkColorPalette
中的颜色分配给特定槽。并非所有槽都需要分配。 - 您的应用可以选择启用 Force Dark,这意味着系统会为您实现深色主题。不过,如果您实现深色主题,可为用户提供更好的体验,以便您能够完全控制应用主题。
- Shapes.kt 是定义应用形状的位置。形状尺寸有三种(小、中、大),您可以指定角的圆角程度。
- 形状能够引导用户注意力、区别组件、传达状态以及表达品牌。
- Types.kt 用于初始化字体并为 Material Design 字体比例分配
fontFamily
、fontWeight
和fontSize
。 - Material Design 字体比例包含一系列对比鲜明的样式,可支持您的应用及其内容的需求。字体比例是字型系统支持的 13 种样式的组合。