1. 开始之前
在本 Codelab 中,您将学习如何使用 Image
可组合项将图像添加到您的应用。
前提条件
- 基本了解如何在 Android Studio 中创建和运行应用。
- 基本了解如何添加 UI 元素,例如文本可组合项。
您将学习到
- 如何将图像或照片添加到您的 Android 应用。
- 如何使用
Image
可组合项在应用中显示图像。 - 使用
String
资源的最佳实践。
您将构建的内容
- 增强“生日快乐”应用,使其包含图像。
您需要准备
- 一台安装了 Android Studio 的计算机。
- 来自使用文本可组合项构建简单的应用 Codelab 的应用。
2. 设置应用
在 Android Studio 中打开您在上一个 Codelab 中创建的“生日快乐”项目。
运行应用后,它应该如下面的屏幕截图所示。
将图像添加到您的项目
在此任务中,您将从互联网下载一张图像并将其添加到您的“生日快乐”应用中。
- 从此链接打开生日贺卡应用所需的图像。
- 点击 下载。
- 右键点击图像,然后将文件保存到您的计算机上,文件名为
androidparty.png
。 - 记下您保存图像的位置。
例如,您可能已将其保存在您的下载文件夹中。
- 在 Android Studio 中,点击 视图 > 工具窗口 > 资源管理器 或点击 项目 窗口旁边的 资源管理器 选项卡。
- 点击 + (向模块添加资源) > 导入可绘制对象。
- 在文件浏览器中,选择您下载的图像文件,然后点击 打开。
此操作将打开导入可绘制对象对话框。
- Android Studio 会向您显示图像预览。从 限定符类型 下拉列表中选择 密度。稍后您会了解到这样做的原因。
- 从 值 列表中选择 无密度。
Android 设备具有不同的屏幕尺寸(例如手机、平板电脑和电视),其屏幕也具有不同的像素尺寸。也就是说,一台设备每平方英寸有 160 像素,而另一台设备在相同的空间内可以容纳 480 像素。如果不考虑这些像素密度差异,系统可能会缩放您的图像,这可能导致图像模糊、消耗过多内存的大图像或尺寸不当的图像。
当您调整大于 Android 系统能够处理的图像大小时,会抛出内存不足错误。对于照片和背景图像(例如当前图像 androidparty.png
),应将其放置在 drawable-nodpi
文件夹中,这将停止缩放行为。
有关像素密度的更多信息,请参阅支持不同的像素密度。
- 点击 下一步。
- Android Studio 会向您显示图像将被放置的文件夹结构。请注意
drawable-nodpi
文件夹。 - 点击 导入(C)。
Android Studio 会创建一个 drawable-nodpi
文件夹并将您的图像放入其中。在 Android Studio 项目视图中,资源名称显示为 androidparty.png (nodpi)
。在计算机文件系统中,Android Studio 会创建一个名为 drawable-nodpi
的文件夹。
如果图像成功导入,Android Studio 会将图像添加到可绘制对象选项卡下的列表中。此列表包含应用的所有图像和图标。您现在可以在应用中使用此图像了。
- 切换回项目视图,点击 视图 > 工具窗口 > 项目 或点击最左侧的 项目 选项卡。
- 点击 app > res > drawable 以确认图像位于
drawable
文件夹中。
3. 添加 Image 可组合项
要在应用中显示图像,它需要一个显示位置。就像您使用 Text
可组合项来显示文本一样,您可以使用 Image
可组合项来显示图像。
在此任务中,您将向应用添加一个 Image
可组合项,将其图像设置为您下载的图像,并定位和调整其大小,使其填充屏幕。
添加可组合函数以添加图像
- 在
MainActivity.kt
文件中,在GreetingText()
函数之后添加一个GreetingImage()
可组合函数。 - 向
GreetingImage()
函数传递两个String
参数:一个用于生日问候,名为message
;另一个用于您的签名,名为from
。
@Composable
fun GreetingImage(message: String, from: String) {
}
- 每个可组合函数都应接受一个可选的
Modifier
参数。修饰符告诉 UI 元素在其父布局中如何布局、显示或行为。在GreetingImage()
可组合项中添加另一个参数。
@Composable
fun GreetingImage(message: String, from: String, modifier: Modifier = Modifier) {
}
Jetpack Compose 中的资源
资源是您的代码使用的额外文件和静态内容,例如位图、用户界面字符串、动画指令等等。有关 Android 资源的更多信息,请参阅应用资源概览。
您应始终将应用资源(例如图像和字符串)与代码分开,以便独立维护它们。在运行时,Android 会根据当前配置使用适当的资源。例如,您可能希望根据屏幕尺寸提供不同的 UI 布局,或根据语言设置提供不同的字符串。
资源分组
您应始终将每种类型的资源放置在项目 res/
目录下的特定子目录中。例如,这是一个简单项目的文件层次结构
MyProject/
src/
MyActivity.kt
res/
drawable/
graphic.png
mipmap/
icon.png
values/
strings.xml
如本例所示,res/
目录包含所有资源,这些资源位于子目录中,包括用于图像资源的 drawable/
目录、用于启动器图标的 mipmap/
目录以及用于字符串资源的 values/
目录。要了解有关应用资源的用法、格式和语法的更多信息,请参阅资源类型概览。
访问资源
Jetpack Compose 可以访问 Android 项目中定义的资源。可以通过项目 R
类中生成的资源 ID 来访问资源。
一个 R
类是 Android 自动生成的类,其中包含项目中所有资源的 ID。在大多数情况下,资源 ID 与文件名相同。例如,可以使用以下代码访问上一个文件层次结构中的图像
R.drawable.graphic
在下一个任务中,您将使用您在上一个任务中添加的图像文件 androidparty.png
。
- 在
GreetingImage()
函数中,声明一个val
属性并将其命名为image
。 - 通过传入
androidparty
资源来调用painterResource()
函数。将返回的值赋给image
变量。
val image = painterResource(R.drawable.androidparty)
Android Studio 突出显示了 .painterResource
代码,因为您需要导入该函数才能编译您的应用。
- 点击 Android Studio 突出显示的
.painterResource
。 - 在弹出窗口中点击 导入 以添加
androidx.compose.ui.res.painterResource
的导入。
painterResource()
函数加载可绘制图像资源,并接受资源 ID(在本例中为 R.drawable.androidparty
)作为参数。
- 调用
painterResource()
函数后,添加一个Image
可组合项,然后将image
作为painter
的命名参数传入。
Image(
painter = image
)
Android Studio 突出显示了 Image
代码,因为您需要导入该函数才能编译您的应用。
要解决此警告,请在 MainActivity.kt
文件的顶部添加以下导入
import androidx.compose.foundation.Image
最初的警告现已解决,但如果您将鼠标悬停在 Image
一词上,Android Studio 会显示一个新警告,指出“提供的参数无法调用以下任何函数”。这是因为提供的参数与任何 Image
函数签名都不匹配。
此警告将在下一节中解决。
检查应用的可访问性
当您遵循可访问性编码实践时,您可以让所有用户(包括残障人士)更轻松地浏览和使用您的应用。
Android Studio 提供提示和警告,帮助您使应用更具可访问性。内容说明定义了 UI 元素的用途,这使得您的应用更易于与 TalkBack 一起使用。
但是,此应用中的图像仅用于装饰目的。在这种特殊情况下,为图像添加内容说明会使与 TalkBack 一起使用变得更加困难。您无需设置向用户宣布的内容说明,而是可以将图像的 contentDescription
参数设置为 null
,以便 TalkBack 跳过 Image
可组合项。
- 在
Image
可组合项中,添加另一个名为contentDescription
的命名参数,并将其值设置为null
。
Image(
painter = image,
contentDescription = null
)
预览 Image 可组合项
在此任务中,您将预览图像可组合项并在模拟器或设备上运行应用。
- 在
BirthdayCardPreview()
函数中,用GreetingImage()
函数调用替换GreetingText()
函数调用。
您的函数应如下面的代码片段所示
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
HappyBirthdayTheme {
GreetingImage(
message = "Happy Birthday Sam!",
from = "From Emma"
)
}
}
- 设计窗格应自动更新,如果未更新,请点击
进行构建。
请注意,您看不到文本了,因为新函数只有 Image
可组合项,而没有 Text
可组合项。
4. 添加 Box 布局
Compose 中有三个基本的标准布局元素:Column
、Row
和 Box
可组合项。您在上一个 Codelab 中了解了 Column
和 Row
可组合项,现在您将深入了解 Box
可组合项。
Box
布局是 Compose 中的标准布局元素之一。使用 Box
布局可以将元素堆叠在一起。Box
布局还允许您配置其中元素的特定对齐方式。
- 在
GreetingImage()
函数中,在Image
可组合项周围添加一个Box
可组合项,如下所示
@Composable
fun GreetingImage(message: String, from: String, modifier: Modifier = Modifier) {
val image = painterResource(R.drawable.androidparty)
Box {
Image(
painter = image,
contentDescription = null
)
}
}
- 当 Android Studio 提示时,导入
androidx.compose.foundation.layout.Box
函数。 - 添加代码将
modifier
参数传递给Box
可组合项。
@Composable
fun GreetingImage(message: String, from: String, modifier: Modifier = Modifier) {
val image = painterResource(R.drawable.androidparty)
Box(modifier) {
Image(
painter = image,
contentDescription = null
)
}
}
- 在
Box
可组合项的末尾,调用GreetingText()
函数,并将生日祝福消息、签名和修饰符传递给它,如下所示
@Composable
fun GreetingImage(message: String, from: String, modifier: Modifier = Modifier) {
val image = painterResource(R.drawable.androidparty)
Box(modifier) {
Image(
painter = image,
contentDescription = null
)
GreetingText(
message = message,
from = from,
modifier = Modifier
.fillMaxSize()
.padding(8.dp)
)
}
}
- 请注意设计窗格中的更新预览。
您应该会看到文本和图像。
- 要在模拟器或设备中反映上述更改,请在
onCreate()
函数中,用GreetingImage()
函数调用替换GreetingText()
函数调用。
您的 setContent
块应如下面的代码片段所示
setContent {
HappyBirthdayTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
GreetingImage(
message = "Happy Birthday Sam!",
from = "From Emma"
)
}
}
}
请注意,图像与屏幕一样宽,但图像固定在屏幕顶部。屏幕底部有空白区域,看起来不太美观。在下一个任务中,您将填充屏幕的宽度和高度,并缩放图像以填充整个屏幕。
5. 更改不透明度和缩放图像
在此任务中,您将使图像全屏显示以美化您的应用。要实现这一点,您需要使用 ContentScale
参数。
缩放内容
您已将图像添加到应用中并定位了图像。现在,您需要调整图像的缩放类型,以使其全屏显示,该类型指定了如何调整图像大小。
有相当多的 ContentScale
类型可用。您将使用 ContentScale.Crop
参数缩放,它会统一缩放图像以保持纵横比,使图像的宽度和高度等于或大于屏幕的相应尺寸。
- 为图像添加一个名为
ContentScale
的参数。
Image(
painter = image,
contentDescription = null,
contentScale = ContentScale.Crop
)
- 当 Android Studio 提示时,导入
androidx.compose.ui.layout.ContentScale
接口。 - 查看设计窗格。
图像现在应该填充整个预览屏幕,如本屏幕截图所示
更改不透明度
为了提高应用的对比度,更改背景图像的不透明度。
向 Image
可组合项添加 alpha
参数并将其设置为 0.5F
。
Image(
painter = image,
contentDescription = null,
contentScale = ContentScale.Crop,
alpha = 0.5F
)
请注意图像不透明度的变化。
代码量不少!是时候预览您的辛勤成果了。
运行应用
在设备或模拟器上运行应用。
很好,您成功实现了全屏图像和文本消息。您还更改了图像的不透明度。
布局修饰符
修饰符用于修饰或向 Jetpack Compose UI 元素添加行为。例如,您可以为行、文本或按钮添加背景、内边距或行为。要设置它们,可组合项或布局需要接受一个修饰符作为参数。
在之前的 Codelab 中,您学习了修饰符并使用了内边距修饰符 (Modifier.padding
) 在 Text
可组合项周围添加空间。修饰符功能强大,您将在本路径和未来的路径中看到这一点。
例如,此 Text
可组合项有一个 Modifier
参数,它将背景颜色更改为绿色。
// Example
Text(
text = "Hello, World!",
// Solid element background color
modifier = Modifier.background(color = Color.Green)
)
与上述示例类似,您可以向布局添加修饰符,使用排列和对齐属性来定位子元素。
要在 Row
中设置子项的位置,请设置 horizontalArrangement
和 verticalAlignment
参数。对于 Column
,请设置 verticalArrangement
和 horizontalAlignment
参数。
当布局的大小大于其子项大小的总和时,排列属性用于排列子元素。
例如:当 Column
的大小大于其子项大小的总和时,可以指定 verticalArrangement
来定义 Column
内子项的位置。下面是不同垂直排列方式的图示
类似地,当 Row
的大小大于其子项大小的总和时,可以指定 horizontalArrangement
来定义 Row
内子项的位置。下面是不同水平排列方式的图示
对齐属性用于在布局的开始、中心或末尾对齐子元素。
6. 对齐和排列文本
在此任务中,您将观察您在之前 Codelab 中添加的用于排列应用中文本的代码。
- 在
MainActivity.kt
文件中,滚动到GreetingText()
函数。列中的verticalArrangement
属性设置为Arrangement.Center
。因此,文本内容将居中于屏幕。
@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
Column(
verticalArrangement = Arrangement.Center,
modifier = modifier
) {
Text(
text = message,
fontSize = 100.sp,
lineHeight = 116.sp,
textAlign = TextAlign.Center
)
Text(
text = from,
fontSize = 36.sp,
modifier = Modifier
.padding(16.dp)
.align(alignment = Alignment.End)
)
}
}
内边距
UI 元素会将其自身包裹在其内容周围。为了防止包裹得太紧,您可以指定每一侧的内边距量。
内边距用作修饰符,这意味着您可以将其应用于任何可组合项。对于可组合项的每一侧,padding
修饰符都接受一个可选参数,该参数定义了内边距量。
// This is an example.
Modifier.padding(
start = 16.dp,
top = 16.dp,
end = 16.dp,
bottom = 16.dp
)
- 轮到您了!在
MainActivity.kt
文件中,滚动到调用GreetingText()
函数的位置,并注意内边距属性。
modifier = Modifier
.fillMaxSize()
.padding(8.dp)
- 类似地,请注意在
GreetingText()
函数内部,签名Text
可组合项的内边距。
modifier = Modifier
.padding(16.dp)
.align(alignment = Alignment.End)
7. 采用良好的代码实践
翻译
编写应用时,请务必记住它们可能在某个时候被翻译成其他语言。正如您在之前的 Codelab 中学到的那样,String
数据类型是字符序列,例如 "Happy Birthday Sam!"
。
硬编码字符串是直接写在应用代码中的字符串。硬编码字符串使得将应用翻译成其他语言以及在应用中不同位置重用字符串变得更加困难。您可以将字符串提取到资源文件中来解决这些问题。您无需在代码中硬编码字符串,而是将字符串放入文件中,命名字符串资源,并在需要使用字符串时使用这些名称。即使更改字符串或将其翻译成不同的语言,名称也保持不变。
- 在
MainActivity.kt
文件中,滚动到onCreate()
函数。选择生日祝福语Happy Birthday Sam!
字符串(不带引号)。 - 点击屏幕左侧的灯泡图标。
- 选择 提取字符串资源。
Android Studio 会打开提取资源对话框。在此对话框中,您可以自定义字符串资源的名称以及存储方式的一些详细信息。资源名称字段是您输入字符串名称的地方。资源值字段是您输入实际字符串本身的地方。
- 在提取资源对话框中,将资源名称更改为
happy_birthday_text
。
字符串资源名称应小写,多个单词之间应使用下划线分隔。保留其他设置的默认值。
- 点击 确定。
- 请注意代码中的变化。
硬编码字符串现在替换为对 getString()
函数的调用。
GreetingImage(
message = getString(R.string.happy_birthday_text),
from = "From Emma",
modifier = Modifier.padding(8.dp)
)
- 在项目窗格中,从路径
app > res > values > strings.xml
打开 strings.xml 文件,并注意 Android Studio 创建了一个名为happy_birthday_text
的字符串资源。
<resources>
<string name="app_name">Happy Birthday</string>
<string name="happy_birthday_text">Happy Birthday Sam!</string>
</resources>
strings.xml
文件包含用户在您的应用中看到的一系列字符串。请注意,您的应用名称也是一个字符串资源。通过将所有字符串放在一个位置,您可以更轻松地翻译应用中的所有文本,并更轻松地在应用的不同部分重用字符串。
- 按照相同的步骤提取签名
Text
可组合项的文本,但这次在资源名称字段中输入signature_text
。
您完成的文件应如下面的代码片段所示
<resources>
<string name="app_name">Happy Birthday</string>
<string name="happy_birthday_text">Happy Birthday Sam!</string>
<string name="signature_text">From Emma</string>
</resources>
- 更新
BirthdayCardPreview()
以使用stringResource()
和提取的字符串。
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
HappyBirthdayTheme {
GreetingImage(
message = stringResource(R.string.happy_birthday_text),
from = stringResource(R.string.signature_text)
)
}
}
- 再次运行您的应用,确保它仍然正常工作。
8. 试试这个挑战
很好,您成功将图像添加到您的应用中。这是一个给您的挑战
- 排列或对齐签名文本可组合项,使其居中对齐于屏幕。
您的应用应该看起来像这样
以下是 GreetingText()
函数的解决方案代码供您参考
@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
Column(
verticalArrangement = Arrangement.Center,
modifier = modifier
) {
Text(
text = message,
fontSize = 100.sp,
lineHeight = 116.sp,
textAlign = TextAlign.Center
)
Text(
text = from,
fontSize = 36.sp,
modifier = Modifier
.padding(16.dp)
.align(alignment = Alignment.CenterHorizontally)
)
}
}
9. 获取解决方案代码
“生日快乐”应用的解决方案代码在 GitHub 上。
GitHub 是一项服务,可让开发者管理其软件项目的代码。它使用 Git,一种版本控制系统,用于跟踪代码每个版本所做的更改。如果您曾在Google 文档中查看过文档的版本历史记录,您可以看到进行了哪些编辑以及何时进行的。类似地,您可以跟踪项目中代码的版本历史记录。这对于个人或团队协作项目非常有用。
此 GitHub 链接允许您在线浏览“生日快乐”项目文件或将其下载到您的计算机上。
要下载已完成 Codelab 的代码,您可以使用此 git 命令
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-birthday-card-app.git
或者,您可以将仓库下载为 zip 文件,解压缩并在 Android Studio 中打开它。
如果您想查看解决方案代码,请在 GitHub 上查看。
GitHub 中的分支
在了解什么是分支之前,请先了解什么是仓库或 repo。仓库是您的整个项目(目录和文件),您可以将其克隆(复制)到您的计算机上。分支是您的仓库的一个版本,换句话说,是一条独立的开发线。举例来说,在本课程中,starter 分支是您在 Codelab 期间用于构建的项目版本。main 或 solution 分支是您的项目在 Codelab 结束时的版本,包含完整的解决方案代码。
一个仓库可以包含多个分支,这意味着仓库中有多个版本的代码。
10. 总结
您成功地为您的“生日快乐”应用添加了图像,使用修饰符对齐了文本,遵循了可访问性指南,并使其更易于翻译成其他语言!更重要的是,您完成了创建自己的“生日快乐”应用!在社交媒体上分享您的作品,并使用标签 #AndroidBasics,以便我们看到它!
摘要
- Android Studio 中的资源管理器选项卡可帮助您添加和组织图像及其他资源。
Image
可组合项是用于在应用中显示图像的 UI 元素。Image
可组合项应具有内容说明,以提高应用的可访问性。- 显示给用户的文本(例如生日祝福语)应提取到字符串资源中,以便更轻松地将应用翻译成其他语言。