使用 RecyclerView 创建动态列表 Android Jetpack 的一部分。
RecyclerView 可以让您轻松高效地显示大量数据。您提供数据并定义每个列表项的外观,而 RecyclerView 库会根据需要动态创建元素。
顾名思义,RecyclerView 会回收这些单个的元素。当列表项滚动出屏幕时,RecyclerView 不会销毁其视图。相反, RecyclerView 会对屏幕上滚动的新项重复使用该视图。 RecyclerView 可以提高性能和应用的响应能力, 降低功耗。
关键类
多个类协同工作来构建动态列表。
RecyclerView
是包含与您的数据对应的视图的ViewGroup
。它本身就是一个视图,因此添加RecyclerView
添加到布局中,就像添加任何其他界面元素一样。列表中的每个独立元素都由一个 ViewHolder 对象进行定义。创建 ViewHolder 时,它并没有任何关联的数据。创建 ViewHolder 后,
RecyclerView
会将其绑定到其数据。您可以通过扩展RecyclerView.ViewHolder
来定义 ViewHolder。RecyclerView
会请求视图,并将视图绑定到其数据。 方法是调用 adapter 中的方法。您可以通过扩展RecyclerView.Adapter
来定义 Adapter。布局管理器负责排列列表中的各个元素。您可以使用 RecyclerView 库提供的某个布局管理器,也可以定义自己的布局管理器。布局管理器均基于库的
LayoutManager
抽象类。
您可以在 RecyclerView 示例应用中查看各部分如何组合在一起 (Kotlin) 或 RecyclerView 示例应用 (Java)。
实现 RecyclerView 的步骤
如果您要使用 RecyclerView,则需要执行以下几项操作。 以下各部分对这些概念进行了详细介绍。
确定列表或网格的外观。通常,您可以 使用 RecyclerView 库的某个标准布局管理器。
设计列表中每个元素的外观和行为。根据此设计,扩展
ViewHolder
类。您的ViewHolder
版本提供了列表项的所有功能。您的 ViewHolder 是View
的封装容器,且该视图由RecyclerView
管理。定义用于将您的数据与
ViewHolder
视图相关联的Adapter
。
此外,您还可以使用高级自定义选项根据自己的具体需求定制 RecyclerView。
规划布局
RecyclerView 中的列表项由 LayoutManager
类负责排列。RecyclerView 库提供了三种布局管理器,用于处理最常见的布局情况:
LinearLayoutManager
将各个项排列在一维列表中。GridLayoutManager
将各个项排列在二维网格中:- 如果网格垂直排列,
GridLayoutManager
会尽量使每行中所有元素的宽度和高度相同,但不同的行可以有不同的高度。 - 如果网格水平排列,
GridLayoutManager
会尽量使每列中所有元素的宽度和高度相同,但不同的列可以有不同的宽度。
- 如果网格垂直排列,
StaggeredGridLayoutManager
与GridLayoutManager
类似,但不要求同一行中的列表项具有相同的高度(垂直网格有此要求)或同一列中的列表项具有相同的宽度(水平网格有此要求)。其结果是,同一行或同一列中的列表项可能会错落不齐。
您还需要设计各个项的布局。你需要这个 (如下一部分所述)。
实现适配器和 ViewHolder
确定布局后,您需要实现 Adapter
并
ViewHolder
。这两个类配合使用,共同定义数据的显示方式。ViewHolder
是包含列表中各列表项的布局的 View
的封装容器。Adapter
创建了 ViewHolder
对象,并为这些视图设置数据。将视图与其数据相关联的过程称为“绑定”。
定义适配器时,您可以替换三个关键方法:
onCreateViewHolder()
:每当RecyclerView
需要创建新的ViewHolder
时,它都会调用此方法。此方法会创建并初始化ViewHolder
及其关联的View
,但不会填充视图的内容,因为ViewHolder
此时尚未绑定到具体数据。onBindViewHolder()
:RecyclerView
调用此方法将ViewHolder
与数据相关联。此方法会提取适当的数据,并使用该数据填充 ViewHolder 的布局。例如,如果RecyclerView
显示名称列表, 该方法可能会在列表中找到适当的名称并填充视图 容器的TextView
widget。getItemCount()
:RecyclerView
会调用此方法来获取数据集的大小。例如: 这可能是地址的总数 RecyclerView 使用此方法来确定何时没有更多可 。
下面是一个典型的简单 Adapter 示例,该 Adapter 包含一个显示数据列表的嵌套 ViewHolder
。在本例中,RecyclerView 显示了一个简单的文本元素列表。系统会向 Adapter 传递一个包含文本的字符串数组,
为 ViewHolder
元素添加样式。
Kotlin
class CustomAdapter(private val dataSet: Array<String>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() { /** * Provide a reference to the type of views that you are using * (custom ViewHolder) */ class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { val textView: TextView init { // Define click listener for the ViewHolder's View textView = view.findViewById(R.id.textView) } } // Create new views (invoked by the layout manager) override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder { // Create a new view, which defines the UI of the list item val view = LayoutInflater.from(viewGroup.context) .inflate(R.layout.text_row_item, viewGroup, false) return ViewHolder(view) } // Replace the contents of a view (invoked by the layout manager) override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) { // Get element from your dataset at this position and replace the // contents of the view with that element viewHolder.textView.text = dataSet[position] } // Return the size of your dataset (invoked by the layout manager) override fun getItemCount() = dataSet.size }
Java
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> { private String[] localDataSet; /** * Provide a reference to the type of views that you are using * (custom ViewHolder) */ public static class ViewHolder extends RecyclerView.ViewHolder { private final TextView textView; public ViewHolder(View view) { super(view); // Define click listener for the ViewHolder's View textView = (TextView) view.findViewById(R.id.textView); } public TextView getTextView() { return textView; } } /** * Initialize the dataset of the Adapter * * @param dataSet String[] containing the data to populate views to be used * by RecyclerView */ public CustomAdapter(String[] dataSet) { localDataSet = dataSet; } // Create new views (invoked by the layout manager) @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { // Create a new view, which defines the UI of the list item View view = LayoutInflater.from(viewGroup.getContext()) .inflate(R.layout.text_row_item, viewGroup, false); return new ViewHolder(view); } // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(ViewHolder viewHolder, final int position) { // Get element from your dataset at this position and replace the // contents of the view with that element viewHolder.getTextView().setText(localDataSet[position]); } // Return the size of your dataset (invoked by the layout manager) @Override public int getItemCount() { return localDataSet.length; } }
每个视图项的布局照例在 XML 布局文件中定义。在本例中,应用包含一个 text_row_item.xml
文件,如下所示:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
android:layout_marginLeft="@dimen/margin_medium"
android:layout_marginRight="@dimen/margin_medium"
android:gravity="center_vertical">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/element_text"/>
</FrameLayout>
后续步骤
以下代码段展示了如何使用 RecyclerView
。
Kotlin
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val dataset = arrayOf("January", "February", "March") val customAdapter = CustomAdapter(dataset) val recyclerView: RecyclerView = findViewById(R.id.recycler_view) recyclerView.layoutManager = LinearLayoutManager(this) recyclerView.adapter = customAdapter } }
Java
RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.layoutManager = new LinearLayoutManager(this) recyclerView.setAdapter(customAdapter);
该库还提供了许多方法来自定义您的实现。有关 请参阅高级 RecyclerView 自定义。
其他资源
如需详细了解如何在 Android 平台上进行测试,请参阅以下资源。