Android Kotlin 基础知识:GridLayout 和 RecyclerView

此 Codelab 是“Android Kotlin 基础知识”课程的一部分。如果您按顺序学习这些 Codelab,您将会充分发掘此课程的价值。“Android Kotlin 基础知识”Codelab 着陆页列出了所有课程 Codelab。

简介

RecyclerView 的一个主要优势是让您可以使用布局管理器来控制和修改布局策略。LayoutManager 用于管理 RecyclerView 中各项的排列方式。

RecyclerView 针对常见用例提供开箱即用的布局管理器。例如,对于水平列表和垂直列表您可以使用 LinearLayout,对于网格您可以使用 GridLayout。对于更复杂的用例,您需要实现自定义 LayoutManager

fcf0fc4b78f8650.png

在此 Codelab 中,您将在上一个 Codelab 的睡眠跟踪器应用的基础上进行构建,学习如何使用网格布局(而非列表)显示数据。(如果您没有上一个 Codelab 的应用,可以下载此 Codelab 的起始代码。)

您应当已掌握的内容

您应熟悉以下知识:

  • 使用 ActivityFragmentsViews 构建基本界面
  • 在 fragment 之间导航,并使用 safeArgs 在 fragment 之间传递数据
  • 视图模型、视图模型工厂和转换
  • LiveData 及其观察者
  • 如何创建 Room 数据库,创建 DAO 和定义实体
  • 如何将协程用于数据库任务和其他长时间运行的任务
  • 如何使用 AdapterViewHolder 和项布局实现基本 RecyclerView
  • 如何为 RecyclerView 实现数据绑定
  • 如何创建和使用绑定适配器来转换数据

学习内容

  • 如何使用不同的 LayoutManager 更改数据在 RecyclerView 中的显示方式
  • 如何为您的睡眠数据创建网格布局

实践内容

  • 在本系列上一个 Codelab 的睡眠跟踪器应用的基础上进行构建。
  • 将应用中的 RecyclerView 显示的睡眠数据列表替换为睡眠数据网格。

此睡眠跟踪器应用有两个屏幕,以 fragment 表示,如下图所示。

左侧所示的第一个屏幕包含用于开始和停止跟踪的按钮。这个屏幕会显示用户的一些睡眠数据。Clear 按钮用于永久删除应用针对用户收集的所有数据。右侧所示的第二个屏幕用于选择睡眠质量评分。

此应用采用简化的架构,其中包括一个界面控制器、ViewModel 和 LiveData,以及一个用于保留睡眠数据的 Room 数据库。

49f975f1e5fe689.png

睡眠数据显示在 RecyclerView 中。在此 Codelab 中,您需要更改应用以使用 GridLayout。最终的屏幕将如以下屏幕截图所示。

b0abde98c5f99bf6.png

在上一个 Codelab 中,当您将 RecyclerView 添加到 fragment_sleep_tracker.xml 时,您添加了一个没有任何自定义设置的 LinearLayoutManager。此代码以垂直列表的形式显示数据。

app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"

LinearLayoutManagerRecyclerView 最常用而且最直观的布局管理器,它支持水平和垂直放置子视图。例如,您可以使用 LinearLayoutManager 创建一个图片轮播界面,供用户横向滚动各个图片。

GridLayout

另一个常见用例是需要向用户显示大量数据,您可以使用 GridLayout 执行此操作。RecyclerViewGridLayoutManager 将数据设置成可滚动的网格布局,如下所示。

fcf0fc4b78f8650.png

从设计角度来看,GridLayout 最适合可以用图标或图片表示的列表,例如照片浏览应用中的列表。在睡眠跟踪器应用中,您可以用大图标网格的形式显示每晚的睡眠数据。这种设计让用户可以一目了然地了解自己的睡眠质量。

GridLayout 如何布局列表项

GridLayout 将各列表项分成网格的各个行和列。假定您采用的是垂直滚动方式,默认情况下,一行中的每个列表项会占据一个“span”。有时候,一个列表项可以占据多个 span。在下例中,一个 span 相当于一列的宽度。

在下面的前两个示例中,每一行由三个 span 组成。默认情况下,GridLayoutManager 会在一个 span 中布局每个列表项,直到达到您指定的 span 计数为止。达到 span 计数时,它会换行至下一行。

默认情况下,每一项占用一个 span,但您可以通过指定占用的 span 数来扩大项的宽度。例如,最右侧屏幕的顶部项(如下所示)会占用三个 span。

在此任务中,您将获取在上一个练习中完成的 RecyclerView,并更新它以使用 GridLayoutManager 显示数据。您可以继续使用上一个 Codelab 的睡眠跟踪器应用,也可以从 GitHub 下载 RecyclerViewGridLayout-Starter 应用

第 1 步:更改 LayoutManager

  1. 如果需要,请从 GitHub 下载用于此 Codelab 的 RecyclerViewGridLayout-Starter 应用,并在 Android Studio 中打开项目。
  2. 打开 fragment_sleep_tracker.xml 布局文件。
  3. sleep_list RecyclerView 定义中移除布局管理器。

要删除的代码:

app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager
  1. 打开 SleepTrackerFragment.kt
  2. OnCreateView() 中在 return 语句前面,创建一个新的自上而下垂直的 GridLayoutManager,包含 3 个 Span。

GridLayoutManager 构造函数最多可接受四个参数:上下文(即 activity)、span 数(默认垂直布局中的列数)、方向(默认为垂直方向)以及是否是反向布局(默认为 false)。

val manager = GridLayoutManager(activity, 3, GridLayoutManager.VERTICAL, false)
  1. 在该行的下方,告知 RecyclerView 使用此 GridLayoutManagerRecyclerView 位于绑定对象中,并被命名为 sleepList。(请参见 fragment_sleep_tracker.xml。)
binding.sleepList.layoutManager = manager

第 2 步:更改布局

list_item_sleep_night.xml 中的当前布局每晚使用一整行显示数据。在此步骤中,您需要为网格定义一个更紧凑的方形项布局。

  1. 打开 list_item_sleep_night.xml。使用 Code 视图检查 XML。
  2. 删除 sleep_length TextView,因为新设计不需要它。
  3. 移动 quality_string TextView,使其显示在 ImageView 下方。为此,您必须更新几项内容。quality_string TextViewquality_image ImageView 的最终布局如下:
<ImageView
   android:id="@+id/quality_image"
   android:layout_width="@dimen/icon_size"
   android:layout_height="60dp"
   android:layout_marginTop="8dp"
   android:layout_marginBottom="8dp"
   app:layout_constraintBottom_toBottomOf="parent"
   app:layout_constraintEnd_toEndOf="parent"
   app:layout_constraintStart_toStartOf="parent"
   app:layout_constraintTop_toTopOf="parent"
   tools:srcCompat="@drawable/ic_sleep_5"
   app:sleepImage="@{sleep}"/>

<TextView
   android:id="@+id/quality_string"
   android:layout_width="0dp"
   android:layout_height="20dp"
   android:layout_marginEnd="16dp"
   android:textAlignment="center"
   app:layout_constraintBottom_toBottomOf="parent"
   app:layout_constraintEnd_toEndOf="parent"
   app:layout_constraintHorizontal_bias="0.0"
   app:layout_constraintStart_toStartOf="parent"
   app:layout_constraintTop_toBottomOf="@+id/quality_image"
   app:sleepQualityString="@{sleep}"
   tools:text="Excellent!"/>
  1. Design 视图中,验证 quality_string TextView 是否位于 ImageView 下方。

969906bdadeaa2dd.png

因为您使用的是数据绑定,所以不需要更改 Adapter 中的任何内容。代码应该就能正常运行,并且您的列表应以网格形式显示。

  1. 运行应用并观察睡眠数据在网格中的显示方式。

请注意,ConstraintLayout 仍会占用整个宽度。GridLayoutManager 会根据视图的 span 为其设置固定宽度。GridLayoutManager 会在放置网格、添加空格或裁剪项时尽可能满足所有约束条件。

  1. SleepTrackerFragment.kt 中,在用于创建 GridLayoutManager 的代码中,将 GridLayoutManger 的 span 数量更改为 1。运行应用,您将会得到一个列表。
val manager = GridLayoutManager(activity, 1)
  1. GridLayoutManager 的 span 数量更改为 10 并运行应用。请注意,GridLayoutManager 将在一行中放置 10 个项,但现在项会被裁剪。
  2. 将 span 数量更改为 5,将方向更改为 GridLayoutManager.HORIZONTAL。运行应用并注意水平滚动状况如何。相当不错!它仍需要不同的布局来改善其外观和风格。我们可以将此任务留到后续 Codelab 中执行。
val manager = GridLayoutManager(activity, 5, GridLayoutManager.HORIZONTAL, false)
  1. 别忘了重新将 span 数量设置为 3,将屏幕方向设置为垂直!

Android Studio 项目:RecyclerViewGridLayout

  • 布局管理器可用于确定 RecyclerView 中各项的排列方式。
  • RecyclerView 附带适用于常见用例的内置布局管理器,例如用于水平列表和垂直列表的 LinearLayout,以及用于网格的 GridLayout
  • 对于更复杂的用例,您可以实现自定义 LayoutManager
  • 从设计角度来看,GridLayout 最适用于可以用图标或图片表示的项的列表。
  • GridLayout 将各列表项分成网格的各个行和列。假设采用垂直滚动方式,一行中的每一项都会占据一个“span”。
  • 您可以自定义某个项占用的 span 数量,从而创建更有趣的网格,而无需自定义布局管理器。
  • 为网格中的一项创建项布局,布局管理器会负责排列这些项。
  • 您可以在包含 <RecyclerView> 元素的 XML 布局文件中为 RecyclerView 设置 LayoutManager,也可以用程序化方式进行设置。

Udacity 课程:

Android 开发者文档:

此部分列出了在由教师指导的课程教学中,学生完成此 Codelab 后可能需要做的家庭作业。教师自行决定是否执行以下措施:

  • 根据需要布置作业。
  • 告知学生如何提交家庭作业。
  • 给家庭作业评分。

教师可以酌情采用这些建议,并且可以自由布置自己认为合适的任何其他家庭作业。

如果您是在自学此 Codelab,可随时通过这些家庭作业来检测您的知识掌握情况。

回答以下问题

问题 1

以下哪些是 Android 提供的布局管理器?请选择所有适用的选项。

LinearLayoutManager

GridLayoutManager

CircularLayoutManager

StaggeredGridLayoutManager

问题 2

什么是“span”?

GridLayoutManager 创建的网格的大小。

▢ 网格中列的宽度。

▢ 网格中项的尺寸。

▢ 垂直方向网格中的列数。

开始学习下一课:与 RecyclerView 项进行交互