RecyclerView 部件和功能
RecyclerView
在内部处理一些任务 (,例如滚动和回收视图) ,但它本质上是一个管理器来协调帮助程序类以显示集合。 RecyclerView
将任务委托给以下帮助程序类:
Adapter
– 扩充项布局 (实例化布局文件) 的内容,并将数据绑定到 在 中显示的RecyclerView
视图。 适配器还会报告项单击事件。LayoutManager
– 度量和定位中的RecyclerView
项视图,并管理视图回收策略。ViewHolder
- 查找和存储视图引用。 视图持有者还有助于检测项目视图单击次数。ItemDecoration
– 允许应用向特定视图添加特殊的绘图和布局偏移量,以便在项、突出显示和视觉分组边界之间绘制分隔线。ItemAnimator
– 定义在项操作期间或对适配器进行更改时发生的动画。
下图描述了 、 LayoutManager
和 Adapter
类之间的关系RecyclerView
:
如此图所示, LayoutManager
可以视为 和 RecyclerView
之间的Adapter
中介。 代表 LayoutManager
对 方法RecyclerView
进行调用Adapter
。 例如, LayoutManager
当需要为 中的特定项位置创建新视图时, RecyclerView
调用 Adapter
方法。 放大 Adapter
该项的布局,并创建一个 ViewHolder
实例, (不显示) 缓存对该位置的视图的引用。 LayoutManager
Adapter
调用 以将特定项绑定到数据集时,会Adapter
查找该项的数据,从数据集中检索数据,并将其复制到关联的项视图。
在应用中使用 RecyclerView
时,需要创建以下类的派生类型:
RecyclerView.Adapter
– 提供从应用的数据集 (绑定,该绑定特定于你的应用,) 到 中显示的RecyclerView
项视图。 适配器知道如何将 中的每个RecyclerView
项视图位置关联到数据源中的特定位置。 此外,适配器还处理每个单独的项目视图中内容的布局,并为每个视图创建视图持有者。 适配器还会报告项视图检测到的项单击事件。RecyclerView.ViewHolder
– 缓存对项布局文件中视图的引用,以便资源查找不会不必要地重复。 当用户点击视图持有人的关联项目视图时,视图持有者还会安排将项目单击事件转发到适配器。RecyclerView.LayoutManager
– 将项定位在 内RecyclerView
。 可以使用多个预定义布局管理器之一,也可以实现自己的自定义布局管理器。RecyclerView
将布局策略委托给布局管理器,因此无需对应用进行重大更改即可插入其他布局管理器。
此外,还可以选择扩展以下类,以更改应用中的外观 RecyclerView
:
RecyclerView.ItemDecoration
RecyclerView.ItemAnimator
如果不扩展 ItemDecoration
和 ItemAnimator
, RecyclerView
则使用默认实现。 本指南不介绍如何创建自定义 ItemDecoration
类和 ItemAnimator
类;有关这些类的详细信息,请参阅 RecyclerView.ItemDecoration 和 RecyclerView.ItemAnimator。
视图回收的工作原理
RecyclerView
不会为数据源中的每个项分配项视图。 相反,它只分配适合在屏幕上的项视图数,并在用户滚动时重复使用这些项目布局。 当视图首次滚动出视线时,它将经历下图所示的回收过程:
当视图滚动出视线并且不再显示时,它将成为 废品视图。
废品视图放置在池中,并成为 回收视图。 此池是显示相同数据类型的视图的缓存。
显示新项时,将从回收池中获取视图以供重复使用。 由于此视图必须在显示之前由适配器重新绑定,因此它称为脏视图。
回收脏视图:适配器查找要显示的下一项的数据,并将此数据复制到该项目的视图。 这些视图的引用从与回收视图关联的视图持有者中检索。
回收的视图将添加到 中即将在屏幕上显示的项目
RecyclerView
列表中。当用户滚动
RecyclerView
到列表中的下一项时,回收的视图将在屏幕上显示。 同时,另一个视图滚动出视线,并根据上述步骤回收。
除了项目视图重用外, RecyclerView
还使用另一个效率优化:视图持有者。 视图持有者是缓存视图引用的简单类。 每次适配器扩充项目布局文件时,它还会创建相应的视图持有者。 视图持有者使用 FindViewById
获取对膨胀项布局文件中视图的引用。 每次回收布局以显示新数据时,这些引用用于将新数据加载到视图中。
布局管理器
布局管理器负责在显示中 RecyclerView
定位项目;它确定列表或网格) (呈现类型、方向 (项目是垂直显示还是水平显示) ,以及哪些方向项应按正常顺序或反向顺序) (显示。 布局管理器还负责计算 RecycleView 显示中每个项的大小和位置。
布局管理器还有一个附加用途:它确定何时回收用户不再可见的项目视图的策略。 由于布局管理器知道哪些视图 (可见,哪些视图不) ,因此它最适合决定何时可以回收视图。 为了回收视图,布局管理器通常会调用适配器,以将已回收视图的内容替换为不同的数据,如前面 视图回收的工作原理中所述。
可以扩展 RecyclerView.LayoutManager
以创建自己的布局管理器,也可以使用预定义的布局管理器。 RecyclerView
提供以下预定义布局管理器:
LinearLayoutManager
– 排列可垂直滚动的列或可水平滚动的行中的项。GridLayoutManager
– 显示网格中的项。StaggeredGridLayoutManager
– 在交错网格中显示项目,其中某些项具有不同的高度和宽度。
若要指定布局管理器,请实例化所选布局管理器并将其传递给 SetLayoutManager
方法。 请注意, 必须 指定布局管理器 - RecyclerView
默认情况下不选择预定义的布局管理器。
有关布局管理器的详细信息,请参阅 RecyclerView.LayoutManager 类参考。
视图持有人
视图持有者是为缓存视图引用定义的类。 适配器使用这些视图引用将每个视图绑定到其内容。 中的每个 RecyclerView
项都有一个关联的视图持有者实例,用于缓存该项的视图引用。 若要创建视图持有者,请使用以下步骤定义一个类,以保存每个项的确切视图集:
- 子类
RecyclerView.ViewHolder
。 - 实现查找和存储视图引用的构造函数。
- 实现适配器可用于访问这些引用的属性。
基本回收器视图示例中ViewHolder
提供了实现的详细示例。
有关 的详细信息 RecyclerView.ViewHolder
,请参阅 RecyclerView.ViewHolder 类参考。
适配器
大多数集成代码的 RecyclerView
“繁重任务”都发生在适配器中。 RecyclerView
要求提供派生自 RecyclerView.Adapter
的适配器来访问数据源,并使用数据源中的内容填充每个项。
由于数据源特定于应用,因此必须实现了解如何访问数据的适配器功能。 适配器从数据源中提取信息,并将其加载到集合中的每个项中 RecyclerView
。
下图演示了适配器如何通过视图持有者将数据源中的内容映射到 中每个行项内的 RecyclerView
单个视图:
适配器加载每 RecyclerView
一行以及特定行项的数据。 例如,对于行位置 P,适配器在数据源中的位置 P 处找到关联的数据,并将此数据复制到集合中位置 P 处的 RecyclerView
行项。
例如,在上面的绘图中,适配器使用视图持有人查找 位于该位置的 和 TextView
的引用ImageView
,因此在用户滚动浏览集合并重用视图时,它不必重复调用FindViewById
这些视图。
实现适配器时,必须重写以下 RecyclerView.Adapter
方法:
OnCreateViewHolder
– 实例化项目布局文件和视图持有者。OnBindViewHolder
– 将指定位置的数据加载到其引用存储在给定视图持有者中的视图中。ItemCount
– 返回数据源中的项数。
布局管理器在 将项定位在 内 RecyclerView
时调用这些方法。
通知 RecyclerView 数据更改
RecyclerView
当数据源的内容发生更改时,不会自动更新其显示;当数据集发生更改时,适配器必须发出通知 RecyclerView
。 数据集可以通过多种方式更改:例如,项内的内容可能会更改,或者数据的整体结构可能会更改。
RecyclerView.Adapter
提供了许多可以调用的方法, RecyclerView
以便以最有效的方式响应数据更改:
NotifyItemChanged
– 指示位于指定位置的项已更改。NotifyItemRangeChanged
– 指示指定位置范围内的项已更改。NotifyItemInserted
– 指示指定位置的项已新插入。NotifyItemRangeInserted
– 指示指定位置范围内的项已新插入。NotifyItemRemoved
– 指示位于指定位置的项已被移除。NotifyItemRangeRemoved
– 指示指定位置范围内的项已被移除。NotifyDataSetChanged
– 指示数据集已更改 (强制) 完全更新。
如果确切地知道数据集的更改情况,则可以调用上述适当方法以最有效的方式刷新 RecyclerView
。 如果不知道数据集的确切变化情况,可以调用 NotifyDataSetChanged
,这效率要低得多,因为 RecyclerView
必须刷新用户可见的所有视图。 有关这些方法的详细信息,请参阅 RecyclerView.Adapter。
在下一主题 基本 RecyclerView 示例中,实现了一个示例应用来演示上面概述的部件和功能的真实代码示例。