添加可滚动列表

1. 开始之前

在本 Codelab 中,您将学习如何使用 Jetpack Compose 在应用中创建可滚动列表。

您将使用 Affirmations 应用,该应用显示一系列搭配精美图片的励志格言,为您的日常生活带来积极能量!

数据已经准备就绪,您只需获取这些数据并在 UI 中显示即可。

先决条件

  • 熟悉 Kotlin 中的列表
  • 使用 Jetpack Compose 构建布局的经验
  • 在设备或模拟器上运行应用的经验

您将学到什么

  • 如何使用 Jetpack Compose 创建 Material Design 卡片
  • 如何使用 Jetpack Compose 创建可滚动列表

您将构建什么

  • 您将获取现有应用程序并在 UI 中添加可滚动列表

最终产品将如下所示

f6f09800b74f4700.png

您需要什么

  • 一台连接互联网的电脑、一个网络浏览器和 Android Studio
  • 访问 GitHub

下载起始代码

在 Android Studio 中,打开 basic-android-kotlin-compose-training-affirmations 文件夹。

  1. 导航到项目提供的 GitHub 存储库页面。
  2. 验证分支名称是否与 Codelab 中指定的分支名称匹配。例如,在以下屏幕截图中,分支名称为 main

1e4c0d2c081a8fd2.png

  1. 在项目的 GitHub 页面上,点击 Code 按钮,这将弹出一个弹出窗口。

1debcf330fd04c7b.png

  1. 在弹出窗口中,点击 Download ZIP 按钮将项目保存到您的电脑。等待下载完成。
  2. 找到电脑上的文件(可能在 Downloads 文件夹中)。
  3. 双击 ZIP 文件以解压缩。这将创建一个包含项目文件的新文件夹。

在 Android Studio 中打开项目

  1. 启动 Android Studio。
  2. 欢迎使用 Android Studio 窗口中,点击 打开

d8e9dbdeafe9038a.png

注意:如果 Android Studio 已经打开,则选择 文件 > 打开 菜单选项。

8d1fda7396afe8e5.png

  1. 在文件浏览器中,导航到解压缩的项目文件夹所在的目录(可能在您的 Downloads 文件夹中)。
  2. 双击该项目文件夹。
  3. 等待 Android Studio 打开项目。
  4. 点击 运行 按钮 8de56cba7583251f.png 以构建并运行应用。确保应用按预期构建。

2. 创建列表项数据类

为 Affirmation 创建数据类

在 Android 应用中,列表由列表项组成。对于单个数据片段,这可能很简单,例如字符串或整数。对于包含多个数据片段的列表项(如图像和文本),您将需要一个包含所有这些属性的类。数据类是一种仅包含属性的类,它们可以提供一些实用方法来处理这些属性。

  1. com.example.affirmations 下创建一个新包。 4a51cb670bbec405.png

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

9ea1f8880ca90ea0.png

  1. com.example.affirmations.model 包中创建一个新类。 a9515a8b47715a22.png

将新类命名为 Affirmation 并将其设为 数据类

b36be7f428fd1672.png

  1. 每个 Affirmation 由一个图像和一个字符串组成。在 Affirmation 数据类中创建两个 val 属性。一个应命名为 stringResourceId,另一个应命名为 imageResourceId。它们都应为整数。

Affirmation.kt

data class Affirmation(
   val stringResourceId: Int,
   val imageResourceId: Int
)
  1. 使用 @StringRes 注解标记 stringResourceId 属性,并使用 @DrawableRes 标记 imageResourceIdstringResourceId 表示存储在字符串资源中的励志格言文本的 ID。 imageResourceId 表示存储在可绘制资源中的励志格言图像的 ID。

Affirmation.kt

data class Affirmation(
   @StringRes val stringResourceId: Int,
   @DrawableRes val imageResourceId: Int
)
  1. 现在打开 com.example.affirmations.data 包中的 Datasource.kt 文件,并取消注释 Datasource 类的内容。

Datasource.kt

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 卡片将如下所示

95111184aed54fa3.png

卡片显示一个图像,下方有一些文本。可以使用包含在 Card 可组合项中的 Column 可组合项实现此垂直布局。您可以自己尝试一下,也可以按照以下步骤操作。

  1. 打开 MainActivity.kt 文件。

1e348baaf91552f4.png

  1. AffirmationApp() 方法下方创建一个新方法,命名为 AffirmationCard(),并使用 @Composable 注解进行注释。

MainActivity.kt

@Composable
fun AffirmationApp() {
   val context = LocalContext.current
   AffirmationsTheme {
    
   }
}

@Composable
fun AffirmationCard() {
  
}
  1. 编辑方法签名以将 Affirmation 对象作为参数。 Affirmation 对象来自 model 包。

MainActivity.kt

@Composable
fun AffirmationCard(affirmation: Affirmation) {
  
}
  1. 向签名中添加一个 modifier 参数。为参数设置一个默认值 Modifier

MainActivity.kt

@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
  
}
  1. AffirmationCard 方法内部,调用 Card 可组合项。传入以下参数: modifierelevation。为 modifier 参数传入一个带有 padding 属性设置为 8.dpModifier 对象。为 elevation 传入值 4.dpelevation 属性将在后面详细介绍。

MainActivity.kt

@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {Card(modifier = modifier.padding(8.dp), elevation = 4.dp) {
  }
}
  1. Card 可组合项内部添加一个 Column 可组合项。 Column 可组合项中的项目在 UI 中垂直排列。这使您可以将图像放置在关联文本的上方。相反, Row 可组合项会水平排列其包含的项目。

MainActivity.kt

@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
  Card(modifier = modifier.padding(8.dp), elevation = 4.dp) {
    Column {
    }
  }
}
  1. Column 可组合项的 lambda 主体内部添加一个 Image 可组合项。请记住, Image 可组合项始终需要一个要显示的资源和一个 contentDescription。该资源应为传递给 painter 参数的 painterResourcepainterResource 方法将加载矢量可绘制对象或诸如 PNG 之类的栅格化资产格式。此外,为 contentDescription 参数传入一个 stringResource

MainActivity.kt

@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
  Card(modifier = Modifier.padding(8.dp), elevation = 4.dp) {
    Column {
      Image(
        painter = painterResource(affirmation.imageResourceId),
        contentDescription = stringResource(affirmation.stringResourceId)
      )
    }
  }
}
  1. 除了 paintercontentDescription 参数外,还可以传入 modifiercontentScalecontentScale 确定如何缩放和显示图像。 Modifier 对象应具有设置为 fillMaxWidth 的属性和高度 194.dpcontentScale 应为 ContentScale.Crop

MainActivity.kt

@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
  Card(modifier = Modifier.padding(8.dp), elevation = 4.dp) {
    Column {
      Image(
        painter = painterResource(affirmation.imageResourceId),
        contentDescription = stringResource(affirmation.stringResourceId),
        modifier = Modifier
          .fillMaxWidth()
          .height(194.dp),
        contentScale = ContentScale.Crop
      )
    }
  }
}
  1. Column 内部,在 Image 可组合项之后创建一个 Text 可组合项。将 affirmation.stringResourceIdstringResource 传递给 text 参数,传递一个具有 padding 属性设置为 16.dpModifier 对象,并通过将 MaterialTheme.typography.h6 传递给 style 参数来设置文本主题。

MainActivity.kt

@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
  Card(modifier = Modifier.padding(8.dp), elevation = 4.dp) {
    Column {
      Image(
        painter = painterResource(affirmation.imageResourceId),
        contentDescription = stringResource(affirmation.stringResourceId),
        modifier = Modifier
          .fillMaxWidth()
          .height(194.dp),
        contentScale = ContentScale.Crop
      )
      Text(
        text = stringResource(affirmation.stringResourceId),
        modifier = Modifier.padding(16.dp),
        style = MaterialTheme.typography.h6
      )
    }
  }
}

预览 AffirmationCard 可组合项

卡片是 Affirmations 应用 UI 的核心,您已经努力创建了它!为了检查卡片是否显示正确,您可以创建一个可组合项,该可组合项可以在不启动整个应用的情况下进行预览。

  1. 创建一个名为 AffirmationCardPreview() 的私有方法。使用 @Preview@Composable 注解该方法。

MainActivity.kt

@Preview 
@Composable
private fun AffirmationCardPreview() {
}
  1. 在方法内部,调用 AffirmationCard 可组合项,并向其传递一个新的 Affirmation 对象,并将 R.string.affirmation1 字符串资源和 R.drawable.image1 可绘制资源传递到其构造函数中。

MainActivity.kt

@Preview 
@Composable
private fun AffirmationCardPreview() {
  AffirmationCard(Affirmation(R.string.affirmation1, R.drawable.image1))
}
  1. 打开“拆分”选项卡,您将看到 AffirmationCard 的预览。如有必要,请在“设计”窗格中单击“构建并刷新”以显示预览。 84904da4a33413ce.png

创建列表

列表项组件是列表的基础构建块。创建列表项后,您可以利用它来创建列表组件本身。

  1. 创建一个名为 AffirmationList() 的方法,使用 @Composable 注解它,并在方法签名中声明一个 Affirmation 对象的 List 作为参数。

MainActivity.kt

@Composable
private fun AffirmationList(affirmationList: List<Affirmation>) {
}
  1. 在方法签名中声明一个 modifier 对象作为参数,其默认值为 Modifier

MainActivity.kt

@Composable
private fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
}
  1. 在 Jetpack Compose 中,可以使用 LazyColumn 可组合项创建可滚动列表。LazyColumnColumn 之间的区别在于,当您要显示少量项目时,应使用 Column,因为 Compose 会一次性加载所有项目。Column 只能容纳预定义或固定的数量的可组合项。LazyColumn 可以根据需要添加内容,这使其非常适合长列表,尤其是在列表长度未知时。LazyColumn 还默认提供滚动功能,无需额外代码。在 AffirmationList() 方法内部声明一个 LazyColumn 可组合项。

MainActivity.kt

@Composable
private fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
  LazyColumn {
  }
}
  1. LazyColumn 的 lambda 体中,调用 items() 方法,并将 affirmationList 传递进去。items() 方法是将项目添加到 LazyColumn 的方法。此方法对于此可组合项来说有些独特,在大多数可组合项中并不是常见的做法。

MainActivity.kt

@Composable
private fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
  LazyColumn {
    items(affirmationList){
    }
  }
}
  1. items() 方法的调用需要一个 lambda 函数。在该函数中,指定一个名为 affirmation 的参数,该参数表示来自 affirmationList 的一个肯定项。

MainActivity.kt

@Composable
private fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
  LazyColumn {
    items(affirmationList){ affirmation ->
    }
  }
}
  1. 对于列表中的每个肯定项,调用 AffirmationCard() 可组合项,并将 affirmation 传递给它。

MainActivity.kt

@Composable
private fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
  LazyColumn {
    items(affirmationList){ affirmation ->
      AffirmationCard(affirmation)
    }
  }
}

显示列表

  1. 在 lambda 中,调用 AffirmationList 可组合项,并将 DataSource().loadAffirmations() 传递给 affirmationList 参数。

MainActivity.kt

@Composable
fun AffirmationApp() {
   AffirmationsTheme {
       Scaffold(
           content = {
               AffirmationList(affirmationList = Datasource().loadAffirmations())
           }
       )
   }
}

在设备或模拟器上运行 Affirmations 应用,查看最终产品!

f6f09800b74f4700.png

4. 获取解决方案代码

如果要查看解决方案代码,请在 GitHub 上查看。

  1. 导航到项目提供的 GitHub 存储库页面。
  2. 验证分支名称是否与 Codelab 中指定的分支名称匹配。例如,在以下屏幕截图中,分支名称为 main

1e4c0d2c081a8fd2.png

  1. 在项目的 GitHub 页面上,点击 Code 按钮,这将弹出一个弹出窗口。

1debcf330fd04c7b.png

  1. 在弹出窗口中,点击 Download ZIP 按钮将项目保存到您的电脑。等待下载完成。
  2. 找到电脑上的文件(可能在 Downloads 文件夹中)。
  3. 双击 ZIP 文件以解压缩。这将创建一个包含项目文件的新文件夹。

在 Android Studio 中打开项目

  1. 启动 Android Studio。
  2. 欢迎使用 Android Studio 窗口中,点击 打开

d8e9dbdeafe9038a.png

注意:如果 Android Studio 已经打开,则选择 文件 > 打开 菜单选项。

8d1fda7396afe8e5.png

  1. 在文件浏览器中,导航到解压缩的项目文件夹所在的目录(可能在您的 Downloads 文件夹中)。
  2. 双击该项目文件夹。
  3. 等待 Android Studio 打开项目。
  4. 点击 运行 按钮 8de56cba7583251f.png 以构建并运行应用。确保应用按预期构建。

5. 结论

您现在知道了如何使用 Jetpack Compose 创建卡片、列表项和可滚动列表!请记住,这些只是创建列表的基本工具。您可以发挥您的创造力,随意自定义列表项!

摘要

  • 使用 Card 可组合项创建列表项。
  • 修改 Card 可组合项内包含的 UI。
  • 使用 LazyColumn 可组合项创建可滚动列表。
  • 使用自定义列表项构建列表。