1. 开始之前
在本 Codelab 中,您将学习如何使用 Jetpack Compose 在您的应用程序中制作可滚动列表。
您将使用 **Affirmations** 应用程序,该应用程序显示与精美图片配对的肯定语,为您的生活带来积极能量!
数据已经存在,您只需获取这些数据并在 UI 中显示它即可。
先决条件
- 熟悉 Kotlin 中的列表
- 使用 Jetpack Compose 构建布局的经验
- 在设备或模拟器上运行应用程序的经验
您将学到什么
- 如何使用 Jetpack Compose 创建一个 Material Design 卡片
- 如何使用 Jetpack Compose 创建一个可滚动列表
您将构建什么
- 您将使用现有应用程序并在 UI 中添加一个可滚动列表
完成的产品将如下所示
您需要什么
- 一台具有互联网访问权限、Web 浏览器和 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** 并将其设为 **数据类**。
- 每个
Affirmation
包含一个图像和一个字符串。在Affirmation
数据类中创建两个val
属性。一个应该称为stringResourceId
,另一个应该称为imageResourceId
。它们都应该是整数。
Affirmation.kt
data class Affirmation(
val stringResourceId: Int,
val imageResourceId: Int
)
- 使用
@StringRes
注解对stringResourceId
属性进行注解,并使用@DrawableRes
注解对imageResourceId
进行注解。stringResourceId
代表存储在字符串资源中的肯定语文本的 ID。imageResourceId
代表存储在可绘制资源中的肯定语图像的 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** 文件并取消注释两个导入语句和
Datasource
类的内容。
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. 在您的应用程序中添加一个列表
创建一个列表项卡片
此应用程序旨在显示肯定语列表。配置 UI 以显示列表的第一步是创建一个列表项。每个肯定语项都包含一个图像和一个字符串。这些项目的每个数据都随入门代码提供,您将创建 UI 组件来显示此类项目。
该项目将包含一个 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
可组合项内的项目在 UI 中垂直排列。这允许您将图像放在关联文本的上面。相反,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
方法将加载矢量可绘制对象或栅格化资产格式,如 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
参数,将具有设置为16.dp
的padding
属性的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** 应用程序 UI 的核心,您已经为此付出了很多努力!要检查卡片是否看起来正确,您可以创建一个可组合项,该项目可以在不启动整个应用程序的情况下进行预览。
- 创建一个名为
AffirmationCardPreview()
的私有方法。使用@Preview
和@Composable
对该方法进行注解。
MainActivity.kt
import androidx.compose.ui.tooling.preview.Preview
@Preview
@Composable
private fun AffirmationCardPreview() {
}
- 在该方法内部,调用
AffirmationCard
可组合项,并将一个新的Affirmation
对象传递给它,该对象在构造函数中传递了R.string.affirmation1
字符串资源和R.drawable.image1
可绘制资源。
MainActivity.kt
@Preview
@Composable
private fun AffirmationCardPreview() {
AffirmationCard(Affirmation(R.string.affirmation1, R.drawable.image1))
}
- 打开 **拆分** 选项卡,您将看到
AffirmationCard
的预览。如果需要,请单击 **设计** 窗格中的 **构建并刷新** 以显示预览。
创建列表
列表项组件是列表的基础。创建列表项后,您可以利用它来制作列表组件本身。
- 创建一个名为
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
和一个具有设置为8.dp
的padding
属性的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
可组合中包含的 UI。 - 使用
LazyColumn
可组合创建可滚动列表。 - 使用自定义列表项构建列表。