1. 准备工作
在此 Codelab 中,您将学习如何使用 Jetpack Compose 在应用中创建可滚动的列表。
您将使用 Affirmations 应用,该应用显示肯定句列表以及精美图片,为您的日常注入积极能量!
数据已经存在,您只需获取这些数据并在界面中显示即可。
前提条件
- 熟悉 Kotlin 中的列表
- 有使用 Jetpack Compose 构建布局的经验
- 有在设备或模拟器上运行应用的经验
学习内容
- 如何使用 Jetpack Compose 创建 Material Design 卡片
- 如何使用 Jetpack Compose 创建可滚动的列表
构建内容
- 您将使用现有应用并在界面中添加可滚动的列表
完成后的产品将如下所示

所需物品
- 一台联网的计算机、一个网页浏览器和 Android Studio
- 访问 GitHub 的权限
下载入门代码
在 Android Studio 中,打开 basic-android-kotlin-compose-training-affirmations 文件夹。
当使用 starter 分支的代码构建时,应用应显示空白屏幕。

2. 创建列表项数据类
为 Affirmation 创建数据类
在 Android 应用中,列表由列表项组成。对于单个数据片段,这可以是一个简单的字符串或整数。对于包含多个数据片段(例如图片和文本)的列表项,您需要一个包含所有这些属性的类。数据类是一种只包含属性的类,它们可以提供一些实用方法来处理这些属性。
- 在 com.example.affirmations 下创建一个新包。

将新包命名为 model. model 包将包含由数据类表示的数据模型。该数据类将由表示与“Affirmation”相关的信息的属性组成,其中包括字符串资源和图片资源。包是包含类甚至其他目录的目录。

- 在 com.example.affirmations.model 包中创建一个新类。

将新类命名为 Affirmation 并使其成为 Data class。

- 每个
Affirmation都包含一张图片和一个字符串。在Affirmation数据类中创建两个val属性。一个应命名为stringResourceId,另一个命名为imageResourceId。它们都应该是整数。
Affirmation.kt
data class Affirmation(
val stringResourceId: Int,
val imageResourceId: Int
)
- 使用
@StringRes注解标注stringResourceId属性,并使用@DrawableRes注解标注imageResourceId。stringResourceId表示存储在字符串资源中的肯定句文本的 ID。imageResourceId表示存储在 drawable 资源中的肯定句图片的 ID。
Affirmation.kt
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
data class Affirmation(
@StringRes val stringResourceId: Int,
@DrawableRes val imageResourceId: Int
)
- 在 com.example.affirmations.data 包中,打开 Datasource.kt 文件并取消注释两个 import 语句和
Datasource类的 contents。
Datasource.kt
import com.example.affirmations.R
import com.example.affirmations.model.Affirmation
class Datasource() {
fun loadAffirmations(): List<Affirmation> {
return listOf<Affirmation>(
Affirmation(R.string.affirmation1, R.drawable.image1),
Affirmation(R.string.affirmation2, R.drawable.image2),
Affirmation(R.string.affirmation3, R.drawable.image3),
Affirmation(R.string.affirmation4, R.drawable.image4),
Affirmation(R.string.affirmation5, R.drawable.image5),
Affirmation(R.string.affirmation6, R.drawable.image6),
Affirmation(R.string.affirmation7, R.drawable.image7),
Affirmation(R.string.affirmation8, R.drawable.image8),
Affirmation(R.string.affirmation9, R.drawable.image9),
Affirmation(R.string.affirmation10, R.drawable.image10))
}
}
3. 向应用添加列表
创建列表项卡片
此应用旨在显示肯定句列表。配置界面以显示列表的第一步是创建列表项。每个肯定句项都包含一张图片和一个字符串。每个项的数据都随入门代码提供,您将创建用于显示此类项的界面组件。
该项将由一个 Card 可组合项组成,其中包含一个 Image 和一个 Text 可组合项。在 Compose 中,Card 是一种在单个容器中显示内容和操作的界面。Affirmation 卡片在预览中的样子如下

卡片下方显示一张图片和一些文本。可以使用包裹在 Card 可组合项中的 Column 可组合项实现此垂直布局。您可以自己尝试,或按照以下步骤实现。
- 打开 MainActivity.kt 文件。
- 在
AffirmationsApp()方法下方创建一个新方法,命名为AffirmationCard(),并使用@Composable注解标注它。
MainActivity.kt
@Composable
fun AffirmationsApp() {
}
@Composable
fun AffirmationCard() {
}
- 编辑方法签名以将
Affirmation对象作为参数。Affirmation对象来自model包。
MainActivity.kt
import com.example.affirmations.model.Affirmation
@Composable
fun AffirmationCard(affirmation: Affirmation) {
}
- 在签名中添加一个
modifier参数。为该参数设置默认值Modifier。
MainActivity.kt
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
}
- 在
AffirmationCard方法内部,调用Card可组合项。传入modifier参数。
MainActivity.kt
import androidx.compose.material3.Card
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
Card(modifier = modifier) {
}
}
- 在
Card可组合项内部添加一个Column可组合项。Column可组合项中的项在界面中垂直排列。这允许您将图片放在相关文本的上方。相反,Row可组合项将其包含的项水平排列。
MainActivity.kt
import androidx.compose.foundation.layout.Column
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
Card(modifier = modifier) {
Column {
}
}
}
- 在
Column可组合项的 lambda 体内部添加一个Image可组合项。请记住,Image可组合项始终需要一个要显示的资源和一个contentDescription。资源应该是传递给painter参数的painterResource。painterResource方法将加载矢量 drawable 或 PNG 等光栅化资产格式。此外,为contentDescription参数传递一个stringResource。
MainActivity.kt
import androidx.compose.foundation.Image
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
Card(modifier = modifier) {
Column {
Image(
painter = painterResource(affirmation.imageResourceId),
contentDescription = stringResource(affirmation.stringResourceId),
)
}
}
}
- 除了
painter和contentDescription参数外,还要传递一个modifier和一个contentScale。contentScale决定了图片应该如何缩放和显示。Modifier对象应设置fillMaxWidth属性,高度为194.dp。contentScale应为ContentScale.Crop。
MainActivity.kt
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.ui.unit.dp
import androidx.compose.ui.layout.ContentScale
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
Card(modifier = modifier) {
Column {
Image(
painter = painterResource(affirmation.imageResourceId),
contentDescription = stringResource(affirmation.stringResourceId),
modifier = Modifier
.fillMaxWidth()
.height(194.dp),
contentScale = ContentScale.Crop
)
}
}
}
- 在
Column内部,在Image可组合项之后创建一个Text可组合项。将affirmation.stringResourceId的stringResource传递给text参数,传递一个设置了padding属性为16.dp的Modifier对象,并通过将MaterialTheme.typography.headlineSmall传递给style参数来设置文本主题。
MainActivity.kt
import androidx.compose.material3.Text
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.platform.LocalContext
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
Card(modifier = modifier) {
Column {
Image(
painter = painterResource(affirmation.imageResourceId),
contentDescription = stringResource(affirmation.stringResourceId),
modifier = Modifier
.fillMaxWidth()
.height(194.dp),
contentScale = ContentScale.Crop
)
Text(
text = LocalContext.current.getString(affirmation.stringResourceId),
modifier = Modifier.padding(16.dp),
style = MaterialTheme.typography.headlineSmall
)
}
}
}
预览 AffirmationCard 可组合项
卡片是 Affirmations 应用界面的核心,您付出了很多努力来创建它!要检查卡片是否正确显示,您可以创建一个无需启动整个应用即可预览的可组合项。
- 创建一个名为
AffirmationCardPreview()的私有方法。使用@Preview和@Composable注解标注该方法。
MainActivity.kt
import androidx.compose.ui.tooling.preview.Preview
@Preview
@Composable
private fun AffirmationCardPreview() {
}
- 在方法内部,调用
AffirmationCard可组合项,并向其传递一个新的Affirmation对象,该对象的构造函数中传入了R.string.affirmation1字符串资源和R.drawable.image1drawable 资源。
MainActivity.kt
@Preview
@Composable
private fun AffirmationCardPreview() {
AffirmationCard(Affirmation(R.string.affirmation1, R.drawable.image1))
}
- 打开 Split 选项卡,您将看到
AffirmationCard的预览。如有必要,在 Design 窗格中点击 Build & Refresh 以显示预览。

创建列表
列表项组件是列表的构建块。创建列表项后,您可以利用它来创建列表组件本身。
- 创建一个名为
AffirmationList()的函数,使用@Composable注解标注它,并在方法签名中声明一个Affirmation对象List作为参数。
MainActivity.kt
@Composable
fun AffirmationList(affirmationList: List<Affirmation>) {
}
- 在方法签名中声明一个
modifier对象作为参数,其默认值为Modifier。
MainActivity.kt
@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
}
- 在 Jetpack Compose 中,可以使用
LazyColumn可组合项创建可滚动的列表。LazyColumn和Column的区别在于,当您要显示的项数量较少时应使用Column,因为 Compose 会一次性加载所有项。Column只能容纳预定义或固定数量的可组合项。LazyColumn可以按需添加内容,这使其适用于长列表,尤其是在列表长度未知时。LazyColumn还默认提供滚动功能,无需额外代码。在AffirmationList()函数内部声明一个LazyColumn可组合项。将modifier对象作为参数传递给LazyColumn。
MainActivity.kt
import androidx.compose.foundation.lazy.LazyColumn
@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
LazyColumn(modifier = modifier) {
}
}
- 在
LazyColumn的 lambda 体中,调用items()方法,并传入affirmationList。items()方法是向LazyColumn添加项的方式。此方法对此可组合项来说有点独特,对于大多数可组合项而言并非通用做法。
MainActivity.kt
import androidx.compose.foundation.lazy.items
@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
LazyColumn(modifier = modifier) {
items(affirmationList) {
}
}
}
- 调用
items()方法需要一个 lambda 函数。在该函数中,指定一个参数affirmation,它代表affirmationList中的一个肯定句项。
MainActivity.kt
@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
LazyColumn(modifier = modifier) {
items(affirmationList) { affirmation ->
}
}
}
- 对于列表中的每个肯定句,调用
AffirmationCard()可组合项。向其传递affirmation和一个设置了padding属性为8.dp的Modifier对象。
MainActivity.kt
@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
LazyColumn(modifier = modifier) {
items(affirmationList) { affirmation ->
AffirmationCard(
affirmation = affirmation,
modifier = Modifier.padding(8.dp)
)
}
}
}
显示列表
- 在
AffirmationsApp可组合项中,检索当前的布局方向并将其保存在一个变量中。稍后将使用它们配置内边距。
MainActivity.kt
import com.example.affirmations.data.Datasource
@Composable
fun AffirmationsApp() {
val layoutDirection = LocalLayoutDirection.current
}
- 现在创建一个
Surface可组合项。此可组合项将为AffirmationsList可组合项设置内边距。
MainActivity.kt
import com.example.affirmations.data.Datasource
@Composable
fun AffirmationsApp() {
val layoutDirection = LocalLayoutDirection.current
Surface() {
}
}
- 将一个
Modifier传递给Surface可组合项,使其填充其父项的最大宽度和高度,设置状态栏内边距,并将开始和结束内边距设置为layoutDirection。以下是将LayoutDirection对象转换为内边距的示例:WindowInsets.safeDrawing.asPaddingValues().calculateStartPadding(layoutDirection)。
MainActivity.kt
import com.example.affirmations.data.Datasource
@Composable
fun AffirmationsApp() {
val layoutDirection = LocalLayoutDirection.current
Surface(
Modifier = Modifier
.fillMaxSize()
.statusBarsPadding()
.padding(
start = WindowInsets.safeDrawing.asPaddingValues()
.calculateStartPadding(layoutDirection),
end = WindowInsets.safeDrawing.asPaddingValues()
.calculateEndPadding(layoutDirection),
),
) {
}
}
- 在
Surface可组合项的 lambda 中,调用AffirmationList可组合项,并将DataSource().loadAffirmations()传递给affirmationList参数。
MainActivity.kt
import com.example.affirmations.data.Datasource
@Composable
fun AffirmationsApp() {
val layoutDirection = LocalLayoutDirection.current
Surface(
Modifier = Modifier
.fillMaxSize()
.statusBarsPadding()
.padding(
start = WindowInsets.safeDrawing.asPaddingValues()
.calculateStartPadding(layoutDirection),
end = WindowInsets.safeDrawing.asPaddingValues()
.calculateEndPadding(layoutDirection),
),
) {
AffirmationsList(
affirmationList = Datasource().loadAffirmations(),
)
}
}
在设备或模拟器上运行 Affirmations 应用,查看成品!

4. 获取解决方案代码
要下载完成的 Codelab 代码,可以使用以下 git 命令
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-affirmations.git $ cd basic-android-kotlin-compose-training-affirmations $ git checkout intermediate
或者,您可以将仓库下载为 ZIP 文件,解压后在 Android Studio 中打开。
如果您想查看解决方案代码,请在 GitHub 上查看。
5. 总结
现在您已了解如何使用 Jetpack Compose 创建卡片、列表项和可滚动列表!请记住,这些只是创建列表的基本工具。您可以发挥创意,随意自定义列表项!
总结
- 使用
Card可组合项创建列表项。 - 修改
Card可组合项中包含的界面。 - 使用
LazyColumn可组合项创建可滚动的列表。 - 使用自定义列表项构建列表。