1. 开始之前
在本 Codelab 中,您将使用 Jetpack Compose 构建一个简单的 Android 应用,该应用会在屏幕上显示生日祝福信息。
先决条件
- 如何在 Android Studio 中创建应用。
- 如何在模拟器或 Android 设备上运行应用。
您将学到什么
- 如何编写可组合函数,例如
Text
、Column
和Row
可组合函数。 - 如何在应用中以布局方式显示文本。
- 如何格式化文本,例如更改文本大小。
您将构建什么
- 一个 Android 应用,该应用以文本格式显示生日祝福信息,完成后的效果如下面的屏幕截图所示
您需要什么
- 安装了 Android Studio 的计算机
2. 设置一个生日快乐应用
在本任务中,您将在 Android Studio 中使用“空活动”模板设置一个项目,并将文本信息更改为个性化的生日祝福信息。
创建“空活动”项目
- 在“欢迎使用 Android Studio”对话框中,选择“新建项目”。
- 在“新建项目”对话框中,选择“空活动”,然后点击“下一步”。
- 在“名称”字段中输入
Happy Birthday
,然后在“最小 SDK”字段中选择最低 API 级别 24(牛轧糖),最后点击“完成”。
- 等待 Android Studio 创建项目文件并构建项目。
- 点击 运行“app”。
该应用的外观应如下面的屏幕截图所示
使用“空活动”模板创建此生日快乐应用时,Android Studio 将为基本的 Android 应用设置资源,包括屏幕上的“Hello Android!”消息。在本 Codelab 中,您将了解该消息是如何显示的,如何将其文本更改为生日祝福信息,以及如何添加和格式化其他消息。
什么是用户界面 (UI)?
应用的用户界面 (UI) 是您在屏幕上看到的内容:文本、图像、按钮以及许多其他类型的元素,以及它们在屏幕上的布局方式。它是应用向用户展示内容的方式,以及用户与应用交互的方式。
此图像包含一个可点击的按钮、文本信息和文本输入字段,用户可以在其中输入数据。
可点击按钮
卡片内的文本信息
文本输入字段
这些元素中的每一个都称为 UI 组件。您在应用屏幕上看到的大部分内容都是 UI 元素(也称为 UI 组件)。它们可以是交互式的,例如可点击的按钮或可编辑的输入字段,也可以是装饰性的图像。
在以下应用中,尝试找到尽可能多的 UI 组件。
在本 Codelab 中,您将使用名为 Text
元素的 UI 元素,它用于显示文本。
3. 什么是 Jetpack Compose?
Jetpack Compose 是一个用于构建 Android UI 的现代工具包。Compose 使用更少的代码、强大的工具和直观的 Kotlin 功能,简化并加速 Android 上的 UI 开发。使用 Compose,您可以通过定义一组函数(称为可组合函数)来构建 UI,这些函数接收数据并描述 UI 元素。
可组合函数
可组合函数是 Compose 中 UI 的基本构建块。可组合函数
- 描述了 UI 的一部分。
- 不返回任何内容。
- 接收一些输入并生成在屏幕上显示的内容。
注释
注释是一种向代码附加额外信息的方式。这些信息有助于像 Jetpack Compose 编译器这样的工具以及其他开发人员了解应用的代码。
注释是通过在要注释的声明开头使用 @
字符添加其名称(注释)来实现的。不同的代码元素,包括属性、函数和类,都可以添加注释。在课程的后续部分,您将了解类。
以下图表是带注释函数的示例
以下代码片段包含带注释属性的示例。您将在接下来的 Codelab 中使用它们。
// Example code, do not copy it over
@Json
val imgSrcUrl: String
@Volatile
private var INSTANCE: AppDatabase? = null
带参数的注释
注释可以接受参数。参数向处理它们的工具提供额外信息。以下是一些带参数和不带参数的 @Preview
注释的示例。
不带参数的注释
预览背景的注释
带预览标题的注释
您可以向注释传递多个参数,如下所示。
Android Studio 屏幕截图显示了代码和预览
带预览标题和系统 UI(手机屏幕)的注释
Jetpack Compose 包含各种内置注释,您已经在本课程中看到了 @Composable
和 @Preview
注释。您将在课程的后面部分学习更多注释及其用法。
可组合函数的示例
可组合函数使用 @Composable
注释进行注释。所有可组合函数都必须添加此注释。此注释告知 Compose 编译器,此函数旨在将数据转换为 UI。提醒一下,编译器是一个特殊的程序,它会读取您编写的代码,逐行查看,并将代码翻译成计算机可以理解的语言(机器语言)。
此代码片段是一个简单的可组合函数的示例,该函数传递数据(name
函数参数)并使用它在屏幕上渲染文本元素。
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
关于可组合函数的一些注意事项
- Jetpack Compose 是围绕可组合函数构建的。这些函数使您能够通过描述 UI 应该是什么样的方式来以编程方式定义应用的 UI,而不是关注 UI 的构建过程。若要创建可组合函数,只需在函数名称中添加
@Composable
注释。 - 可组合函数可以接受参数,这些参数使应用逻辑能够描述或修改 UI。在本例中,您的 UI 元素接受
String
,以便它可以通过姓名来问候用户。
注意代码中的可组合函数
- 在 Android Studio 中,打开
MainActivity.kt
文件。 - 滚动到
GreetingPreview()
函数。此可组合函数有助于预览Greeting()
函数。作为良好的做法,函数应该始终命名或重命名为描述其功能。将此函数的名称更改为BirthdayCardPreview()
。
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
HappyBirthdayTheme {
Greeting("Android")
}
}
可组合函数可以调用其他可组合函数。在此代码片段中,预览函数调用 Greeting()
可组合函数。
请注意,前面的函数还添加了另一个注释,即 @Preview
注释,并在 @Composable
注释之前添加了一个参数。您将在本课程的后面部分详细了解传递给 @Preview
注释的参数。
可组合函数名称
不返回任何内容并添加了 @Composable
注释的 Compose 函数必须使用帕斯卡命名法命名。帕斯卡命名法是一种命名约定,它要求复合词中每个单词的首字母大写。帕斯卡命名法和驼峰命名法之间的区别在于,帕斯卡命名法中所有单词的首字母都大写。在驼峰命名法中,第一个单词可以是大写或小写。
Compose 函数
- 必须是名词:
DoneButton()
- 不能是动词或动词短语:
DrawTextField()
- 不能是名词化的介词:
TextFieldWithLink()
- 不能是形容词:
Bright()
- 不能是副词:
Outside()
- 名词可以添加描述性形容词前缀:
RoundIcon()
要了解更多信息,请参阅 命名可组合函数。
示例代码。请勿复制
// Do: This function is a descriptive PascalCased noun as a visual UI element
@Composable
fun FancyButton(text: String) {}
// Do: This function is a descriptive PascalCased noun as a non-visual element
// with presence in the composition
@Composable
fun BackButtonHandler() {}
// Don't: This function is a noun but is not PascalCased!
@Composable
fun fancyButton(text: String) {}
// Don't: This function is PascalCased but is not a noun!
@Composable
fun RenderFancyButton(text: String) {}
// Don't: This function is neither PascalCased nor a noun!
@Composable
fun drawProfileImage(image: ImageAsset) {}
4. Android Studio 中的设计窗格
Android Studio 允许您在 IDE 内预览可组合函数,而不是将应用安装到 Android 设备或模拟器上。正如您在之前的学习路径中了解到的那样,您可以在 Android Studio 的“设计”窗格中预览应用的外观。
可组合函数必须为任何参数提供默认值才能进行预览。出于这个原因,建议不要直接预览 Greeting()
函数。相反,您需要添加另一个函数(在本例中为 BirthdayCardPreview()
函数),该函数以适当的参数调用 Greeting()
函数。
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
HappyBirthdayTheme {
Greeting("Android")
}
}
若要查看预览
- 在
BirthdayCardPreview()
函数中,将"Android"
参数(在Greeting()
函数中)更改为您的姓名。
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
HappyBirthdayTheme {
Greeting("James")
}
}
- 预览应自动更新。
您应该会看到更新的预览。
5. 添加新的文本元素
在本任务中,您将删除 Hello $name!
问候语并添加生日祝福信息。
添加新的可组合函数
- 在
MainActivity.kt
文件中,删除Greeting()
函数定义。您将在 Codelab 的后面部分添加自己的函数来在代码中显示问候语。
删除以下代码
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
- 在
onCreate()
函数中,请注意Greeting()
函数调用现在显示为红色。红色表示错误。将鼠标悬停在此函数调用上,Android Studio 将显示有关错误的信息。
- 从
onCreate()
和BirthdayCardPreview()
函数中删除Greeting()
函数调用及其参数。您的MainActivity.kt
文件将类似于以下内容
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
HappyBirthdayTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
}
}
}
}
}
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
HappyBirthdayTheme {
}
}
- 在
BirthdayCardPreview()
函数之前,添加一个名为GreetingText()
的新函数。不要忘记在函数之前添加@Composable
注解,因为这将是一个描述Text
可组合的组合函数。
@Composable
fun GreetingText() {
}
- 最佳做法是让您的可组合函数接受一个
Modifier
参数,并将该modifier
传递给它的第一个子元素。您将在后续任务和代码实验室中学习更多关于Modifier
和子元素的知识。现在,在GreetingText()
函数中添加一个Modifier
参数。
@Composable
fun GreetingText(modifier: Modifier = Modifier) {
}
- 在
GreetingText()
可组合函数中添加一个类型为String
的message
参数。
@Composable
fun GreetingText(message: String, modifier: Modifier = Modifier) {
}
- 在
GreetingText()
函数中,添加一个Text
可组合,将文本消息作为命名参数传递。
@Composable
fun GreetingText(message: String, modifier: Modifier = Modifier) {
Text(
text = message
)
}
此 GreetingText()
函数在 UI 中显示文本。它通过调用 Text()
可组合函数来实现。
预览函数
在本任务中,您将在 **设计** 面板中预览 GreetingText()
函数。
- 在
BirthdayCardPreview()
函数内调用GreetingText()
函数。 - 将
String
参数传递给GreetingText()
函数,向您的朋友发送生日祝福。您可以根据需要使用他们的姓名进行自定义,例如"Happy Birthday Sam!"
。
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
HappyBirthdayTheme {
GreetingText(message = "Happy Birthday Sam!")
}
}
- 在 **设计** 面板中自动更新。预览您的更改。
6. 更改字体大小
您已将文本添加到用户界面,但它看起来不像最终的应用程序。在本任务中,您将学习如何更改文本元素的外观,例如大小、文本颜色等。您还可以尝试不同的字体大小和颜色。
可缩放像素
可缩放像素 (SP) 是字体大小的度量单位。Android 应用程序中的 UI 元素使用两种不同的度量单位:与密度无关的像素 (DP)(您将在以后用于布局),以及可缩放像素 (SP)。默认情况下,SP 单位与 DP 单位大小相同,但它会根据用户在手机设置中选择的文本大小进行调整。
- 在
MainActivity.kt
文件中,滚动到GreetingText()
函数中的Text()
可组合。 - 将
fontSize
参数作为第二个命名参数传递给Text()
函数,并将其设置为100.
sp
的值。
Text(
text = message,
fontSize = 100.sp
)
Android Studio 会突出显示 .sp
代码,因为您需要导入一些类或属性才能编译您的应用程序。
- 单击突出显示的 Android Studio 的
.sp
。 - 在弹出窗口中单击 **导入**,以导入 **
androidx.compose.ui.unit.sp
** 以使用.sp
扩展属性。
- 滚动到文件顶部,注意
import
语句,您应该看到一个import androidx.compose.ui.unit.sp
语句,这意味着 Android Studio 将该包添加到您的文件中。
- 注意字体大小的更新预览。消息重叠的原因是您需要指定行高。
- 更新
Text
可组合以包含行高。
@Composable
fun GreetingText(message: String, modifier: Modifier = Modifier) {
Text(
text = message,
fontSize = 100.sp,
lineHeight = 116.sp,
)
}
现在您可以尝试不同的字体大小。
7. 添加另一个文本元素
在之前的任务中,您向您的朋友添加了生日祝福消息。在本任务中,您将用您的姓名签署您的卡片。
- 在
MainActivity.kt
文件中,滚动到GreetingText()
函数。 - 将类型为
String
的from
参数传递给函数,作为您的签名。
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier)
- 在生日祝福消息
Text
可组合之后,添加另一个Text
可组合,它接受设置为from
值的text
参数。
@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
Text(
// ...
)
Text(
text = from
)
}
- 添加一个设置为
36.sp
的值fontSize
命名参数。
Text(
text = from,
fontSize = 36.sp
)
- 滚动到
BirthdayCardPreview()
函数。 - 添加另一个
String
参数来签署您的卡片,例如"From Emma"
。
GreetingText(message = "Happy Birthday Sam!", from = "From Emma")
- 注意预览。
一个可组合函数可能会描述多个 UI 元素。但是,如果您没有提供关于如何排列它们的指导,Compose 可能会以您不喜欢的方式排列这些元素。例如,前面的代码会生成两个相互重叠的文本元素,因为没有关于如何排列这两个可组合的指导。
在下一项任务中,您将学习如何将可组合元素排列成一行和一列。
8. 将文本元素排列成一行和一列
UI 层次结构
UI 层次结构基于包含,这意味着一个组件可以包含一个或多个组件,并且有时会使用父级和子级这两个术语。这里的上下文是父 UI 元素包含子 UI 元素,而子 UI 元素又可以包含子 UI 元素。在本节中,您将学习关于 Column
、Row
和 Box
可组合的知识,它们可以充当父 UI 元素。
Compose 中的三个基本标准布局元素是 Column
、Row
和 Box
可组合。您将在下一个代码实验室中学习更多关于 Box
可组合的知识。
Column
、Row
和 Box
是可组合函数,它们将可组合内容作为参数,因此您可以在这些布局元素内放置项目。例如,Row
可组合内的每个子元素都会水平地彼此相邻地放置在一行中。
// Don't copy.
Row {
Text("First Column")
Text("Second Column")
}
这些文本元素在屏幕上彼此相邻地显示,如本图像所示。
蓝色边框仅用于演示目的,不会显示。
尾随 lambda 语法
请注意,在前面的代码片段中,Row
可组合函数中使用了花括号而不是圆括号。这称为尾随 lambda 语法。您将在本课程的后面详细了解lambda 和尾随 lambda 语法。现在,请熟悉这种常用的 Compose 语法。
Kotlin 为将函数作为参数传递给函数提供了特殊语法,当最后一个参数是函数时。
当您将函数作为该参数传递时,可以使用尾随 lambda 语法。您无需将函数放在圆括号内,而是可以将其放在圆括号外的花括号内。这是 Compose 中的一种推荐做法,也是一种常见做法,因此您需要熟悉代码的外观。
例如,Row()
可组合函数中的最后一个参数是 content
参数,它是一个描述子 UI 元素的函数。假设您要创建一个包含三个文本元素的行。这段代码可以工作,但使用命名参数来使用尾随 lambda 非常繁琐
Row(
content = {
Text("Some text")
Text("Some more text")
Text("Last text")
}
)
由于 content
参数是函数签名中的最后一个参数,并且您将它的值作为 lambda 表达式传递(现在,如果您不知道什么是 lambda,没关系,只要熟悉语法即可),您可以删除 content
参数和圆括号,如下所示
Row {
Text("Some text")
Text("Some more text")
Text("Last text")
}
将文本元素排列成一行
在本任务中,您将在应用程序中将文本元素排列成一行,以避免重叠。
- 在
MainActivity.kt
文件中,滚动到GreetingText()
函数。 - 在文本元素周围添加
Row
可组合,以便显示包含两个文本元素的行。选择两个Text
可组合,单击灯泡。选择 **用小部件包围** > **用 Row 包围**。
现在,该函数应该像此代码片段一样
@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
Row {
Text(
text = message,
fontSize = 100.sp,
lineHeight = 116.sp,
)
Text(
text = from,
fontSize = 36.sp
)
}
}
- Android Studio 会为您自动导入
Row
函数。滚动到顶部,注意导入部分。应该已添加import androidx.compose.foundation.layout.Row
。 - 观察 **设计** 面板中的更新预览。暂时将生日祝福消息的字体大小更改为
30.sp
。
现在,由于没有重叠,预览看起来好多了。但是,这不是您想要的,因为您的签名没有足够的空间。在下一项任务中,您将文本元素排列成一列以解决此问题。
将文本元素排列成一列
在本任务中,您将尝试更改 GreetingText()
函数以将文本元素排列成一列。预览应该看起来像此屏幕截图
既然您已经尝试了独自完成此操作,请随意将您的代码与此代码片段中的解决方案代码进行比较
@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
Column {
Text(
text = message,
fontSize = 100.sp,
lineHeight = 116.sp,
)
Text(
text = from,
fontSize = 36.sp
)
}
}
注意 Android Studio 自动导入的包
import androidx.compose.foundation.layout.Column
请记住,您需要将修饰符参数传递给可组合中的子元素。这意味着您需要将修饰符参数传递给 Column
可组合。
@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
Column(modifier = modifier) {
Text(
text = message,
fontSize = 100.sp,
lineHeight = 116.sp,
)
Text(
text = from,
fontSize = 36.sp
)
}
}
9. 将问候语添加到应用程序
当您对预览感到满意后,就可以将可组合元素添加到设备或模拟器上的应用程序中。
- 在
MainActivity.kt
文件中,滚动到onCreate()
函数。 - 从
Surface
块调用GreetingText()
函数。 - 将您的生日祝福和签名传递给
GreetingText()
函数。
完成后的 onCreate()
函数应该像此代码片段一样
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
HappyBirthdayTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
GreetingText(message = "Happy Birthday Sam!", from = "From Emma")
}
}
}
}
}
- 在模拟器上构建并运行您的应用程序。
将问候语对齐到中心
- 要将问候语对齐到屏幕中央,添加一个名为
verticalArrangement
的参数,将其设置为Arrangement.Center
。您将在后面的代码实验室中学习更多关于verticalArrangement
的知识。
@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
Column(
verticalArrangement = Arrangement.Center,
modifier = modifier
) {
// ...
}
}
- 在列周围添加
8.dp
填充。建议使用以4.dp
为增量的填充值。
@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
Column(
verticalArrangement = Arrangement.Center,
modifier = modifier.padding(8.dp)
) {
// ...
}
}
- 为了进一步美化您的应用程序,使用
textAlign
将问候语文本对齐到中心。
Text(
text = message,
fontSize = 100.sp,
lineHeight = 116.sp,
textAlign = TextAlign.Center
)
在上面的截图中,由于 textAlign
参数,只有问候语是居中对齐的。签名 **From Emma** 使用默认的对齐方式,即左对齐。
- 在签名中添加填充并将其右对齐。
Text(
text = from,
fontSize = 36.sp,
modifier = Modifier
.padding(16.dp)
.align(alignment = Alignment.End)
)
采用最佳实践
最佳实践是在父可组合项中将修饰符属性与修饰符一起传递。更新 GreetingText()
中的修饰符参数,如下所示
onCreate()
Surface(
//...
) {
GreetingText(
message = "Happy Birthday Sam!",
from = "From Emma",
modifier = Modifier.padding(8.dp)
)
}
GreetingText()
@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
Column(
verticalArrangement = Arrangement.Center,
modifier = modifier
) {
// ...
}
}
在模拟器上构建并运行您的应用程序以查看最终结果。
10. 获取解决方案代码
完成的 MainActivity.kt
package com.example.happybirthday
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.happybirthday.ui.theme.HappyBirthdayTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
HappyBirthdayTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
GreetingText(
message = "Happy Birthday Sam!",
from = "From Emma",
modifier = Modifier.padding(8.dp)
)
}
}
}
}
}
@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)
)
}
}
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
HappyBirthdayTheme {
GreetingText(message = "Happy Birthday Sam!", from = "From Emma")
}
}
11. 结论
您创建了“生日快乐”应用程序。
在下一个 codelab 中,您将向应用程序添加图片,并更改文本元素的对齐方式以美化它。
总结
- Jetpack Compose 是用于构建 Android UI 的现代工具包。Jetpack Compose 通过更少的代码、强大的工具和直观的 Kotlin API 简化和加速 Android 上的 UI 开发。
- 应用程序的用户界面 (UI) 是您在屏幕上看到的内容:文本、图像、按钮以及许多其他类型的元素。
- 可组合函数是 Compose 的基本构建块。可组合函数是描述 UI 部分的函数。
- 可组合函数用
@Composable
注释进行注释;此注释通知 Compose 编译器此函数旨在将数据转换为 UI。 - Compose 中的三个基本标准布局元素是
Column
、Row
和Box
。它们是可组合函数,它们接受可组合内容,因此您可以将项目放置在其中。例如,Row
中的每个子项都将水平放置在彼此旁边。