练习:构建超级英雄应用

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

1. 准备工作

恭喜!在本在线课程中,您学习了 Material Design 的基础知识,以及如何在应用中添加简单的动画。现在,该将您学到的知识付诸实践了。

在本练习集中,您将打造一个超级英雄应用,以此学习您在本在线课程中学到的概念。此应用专注于使用您在使用 Jetpack Compose 实现 Material 主题效果 Codelab 中学到的 Material Design 原则,创建构建可滚动列表和精美界面所需的组件。

解决方案代码就在文末,不过建议您先做练习,然后再看答案。不妨将提供的解决方案视为实现应用的方法之一。有很大的改进空间,因此您可以随意尝试不同的方法。

您可以按照自己的节奏来解决问题。我们提供的预估时长仅供参考,您不必一定要在此时间内完成。希望您能尽力而为,认真解决每一个问题。

前提条件

所需条件

  • 一台可连接到互联网并安装了 Android Studio 的计算机。

构建内容

显示超级英雄列表的超级英雄应用。

最终应用在浅色主题和深色主题中应如下所示:

2. 开始

在此任务中,您将设置项目并为超级英雄创建虚拟数据。

  1. 使用 Empty Compose Activity 模板创建一个新 SDK,并将最低 SDK 设为 21。
  2. 此处下载应用的素材资源:超级英雄图片和应用徽标。
  3. https://fonts.google.com 下载 Cabin 粗体和 Cabin 常规字体文件。您可以随意探索不同的字体文件。
  4. 创建数据类以存储每个超级英雄的数据。您可以随意为 Hero 数据类创建一个名为 model 的新软件包来整理您的代码。您的列表项可能如下所示:

5522f986d46e24d0.png

每个超级英雄列表项都会显示三条独特的信息,包括名称、说明和图片。

  1. 在同一 model 软件包中,为您希望显示的所有英雄信息创建另一个文件。例如名称、说明和图片资源。以下是一个能启发您的灵感的示例数据集。
object HeroesRepository {
   val heroes = listOf(
       Hero(
           nameRes = R.string.hero1,
           descriptionRes = R.string.description1,
           imageRes = R.drawable.android_superhero1
       ),
       Hero(
           nameRes = R.string.hero2,
           descriptionRes = R.string.description2,
           imageRes = R.drawable.android_superhero2
       ),
       Hero(
           nameRes = R.string.hero3,
           descriptionRes = R.string.description3,
           imageRes = R.drawable.android_superhero3
       ),
       Hero(
           nameRes = R.string.hero4,
           descriptionRes = R.string.description4,
           imageRes = R.drawable.android_superhero4
       ),
       Hero(
           nameRes = R.string.hero5,
           descriptionRes = R.string.description5,
           imageRes = R.drawable.android_superhero5
       ),
       Hero(
           nameRes = R.string.hero6,
           descriptionRes = R.string.description6,
           imageRes = R.drawable.android_superhero6
       )
   )
}

3. Material 主题设置

在此部分中,您将添加应用的调色板、排版和形状,以改善应用的外观和风格。

颜色

以下只是配色方案的建议。您可以随意选择其他配色方案。

ui.theme.Color.kt

//Light Theme
val md_theme_light_background = Color(0xFFFDFCF4)
val md_theme_light_surface = Color(0xFFE0EACE)
val md_theme_light_secondary = Color(0xFF596148)
val md_theme_light_onSurface = Color(0xFF1B1C18)
val md_theme_light_primary = Color(0xFF466800)
val md_theme_light_onPrimary = Color(0xFF223600)

// Dark Theme
val md_theme_dark_background = Color(0xFF1B1C18)
val md_theme_dark_surface = Color(0xFF373F29)
val md_theme_dark_secondary = Color(0xFFDDE6C6)
val md_theme_dark_onSurface = Color(0xFFE4E3DB)
val md_theme_dark_primary = Color(0xFFC1CAAB)
val md_theme_dark_onPrimary = Color(0xFFDDE6C6)

形状

ui.theme.Shape.kt

import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Shapes
import androidx.compose.ui.unit.dp

val Shapes = Shapes(
   small = RoundedCornerShape(8.dp),
   medium = RoundedCornerShape(16.dp),
   large = RoundedCornerShape(16.dp)
)

排版

ui.theme.Type.kt

import androidx.compose.material.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import com.example.superheroes.R

val Cabin = FontFamily(
   Font(R.font.cabin_regular, FontWeight.Normal),
   Font(R.font.cabin_bold, FontWeight.Bold)
)

// Set of Material typography styles to start with
val Typography = Typography(
   defaultFontFamily = Cabin,
   h1 = TextStyle(
       fontWeight = FontWeight.Normal,
       fontSize = 30.sp
   ),
   h2 = TextStyle(
       fontWeight = FontWeight.Bold,
       fontSize = 20.sp
   ),
   h3 = TextStyle(
       fontWeight = FontWeight.Bold,
       fontSize = 20.sp
   ),

   body1 = TextStyle(
       fontWeight = FontWeight.Normal,
       fontSize = 16.sp
   )
)

主题

ui.theme.Theme.kt

import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material.MaterialTheme
import androidx.compose.material.darkColors
import androidx.compose.material.lightColors
import androidx.compose.runtime.Composable

private val DarkColorPalette = darkColors(
   background = md_theme_dark_background,
   surface = md_theme_dark_surface,
   onSurface = md_theme_dark_onSurface,
   primary = md_theme_dark_primary,
   onPrimary = md_theme_dark_onPrimary,
   secondary = md_theme_dark_secondary
)

private val LightColorPalette = lightColors(
   background = md_theme_light_background,
   surface = md_theme_light_surface,
   onSurface = md_theme_light_onSurface,
   primary = md_theme_light_primary,
   onPrimary = md_theme_light_onPrimary,
   secondary = md_theme_light_secondary
)

@Composable
fun SuperheroesTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
   val colors = if (darkTheme) {
       DarkColorPalette
   } else {
       LightColorPalette
   }

   MaterialTheme(
       colors = colors,
       typography = Typography,
       shapes = Shapes,
       content = content
   )
}

4. 显示列表

创建列表的第一步是创建列表项。

  1. com.example.superheroes 软件包下,创建一个名为 HeroesDataSource.kt 的文件。
  2. 创建一个可组合项来代表超级英雄列表项,类似于以下屏幕截图和界面规范。5522f986d46e24d0.png

请遵照此界面规范,或发挥创意并自行设计列表项:

  • 列表项的高度为 74dp
  • 列表项内边距为 16dp
  • 卡片高度为 2dp
  • 图片和文本之间的间距为 16dp
  • 图片的剪辑半径为 8dp
  • 列表项的裁剪半径为 16dp
  • 超级英雄名称的字体是 H3
  • 超级英雄说明的字体是 Body1

dc6fbb4070f1876.png

d78e2d324242b224.png

创建 lazy 列

  1. 创建另一个可组合项,用于获取英雄列表并显示列表。您可以在此处使用 lazyColumn
  2. 对内边距使用以下界面规范。

591dfc1744afbf98.png

完成实现后,您的应用应与以下屏幕截图一致:

9bf806c163ed3489.png

5. 添加顶部应用栏

为您的应用添加一个顶部应用栏;可以是简单的文字。

  1. MainActivity.kt 中,添加一个可组合项以显示顶部应用栏。在顶部应用栏中添加文字;可以是应用名称。在水平和垂直方向上居中对齐。
  2. 您可以将应用栏的高度设置为 56dp,并将字体设置为 h1,也可以自行设计顶部应用栏。

d6f672e360efe331.png

  1. 使用 scaffold 显示顶部应用栏。如有需要,请参阅文档

自定义状态栏颜色

为使您的应用更优雅,您可以自定义状态栏颜色,使其与背景颜色保持一致。

6. 解决方案代码

如需下载完成后的 Codelab 代码,您可以使用以下 Git 命令:

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-superheroes-app.git

或者,您也可以下载 ZIP 文件形式的代码库,将其解压缩并在 Android Studio 中打开。

如果您想查看解决方案代码,请前往 GitHub 查看