Material Design 的 RecyclerView 详解与实践

阅读时长 17 分钟读完

前言

Material Design 是谷歌在 2014 年推出的一种视觉设计语言,旨在提供一种更加现代、统一、直观和有信息等级感的用户体验。它不仅仅是一种设计语言,还是一种视觉和交互的规范,涉及到 UI 元素、布局、颜色、字体、动画、阴影等各个方面。

在前端开发中,实现 Material Design 可以帮助您在设计上得到更统一、更高质量的用户体验,同时还可以提高开发效率和代码质量。本文将介绍 RecyclerView,这个在 Material Design 中被广泛使用的控件。

什么是 RecyclerView

RecyclerView 是一个强大而灵活的控件,是 Android 5.0(API 级别 21)中的一个新特性,取代了 ListView 和 GridView,并提供了默认的动画效果。它可以用于展示大量数据条目,并支持滚动、布局管理和触摸交互等特性,同时具有更好的性能和可扩展性。

与 ListView 和 GridView 相比,RecyclerView 更加模块化,可以将数据管理、布局管理、视图呈现和用户交互分开处理,实现高度的复用和扩展。它提供了一个可视化的布局管理器(LayoutManager)来定位子视图的位置和大小,可以支持线性、网格、瀑布流等多种布局方式。此外,RecyclerView 还提供了拖拽排序、滑动删除、动态变化等高级功能,可以帮助您更好地实现交互效果。

RecyclerView 的基本使用

添加依赖

在构建.gradle文件中添加依赖:

准备数据

假设我们要展示一个包含图片和文字的列表条目。首先定义一个数据类 Item:

接下来定义一个数据源,包含若干个 Item:

创建布局

接下来,我们需要创建一个列表条目的布局,它包含一个 ImageView 和一个 TextView,使用 LinearLayout 作为根布局:

-- -------------------- ---- -------
------------- ----------------------------------------------------------
              -----------------------------------
              ------------------------------------
              ---------------------
              ---------------------------------

    ----------
        ----------------------------
        ---------------------------
        ----------------------------
        --------------------------------

    ---------
        ----------------------------
        --------------------------
        ------------------------------------
        -------------------------
        -----------------------
        ---------------------------------
        ----------------------------------

---------------

创建适配器

适配器(Adapter)是 RecyclerView 的一个关键组件,它提供了将数据绑定到视图的方法,并管理了列表条目的创建、更新和删除。我们需要定义一个适配器,将数据源中的每个 Item 显示到列表中。

先创建一个 ViewHolder,用于缓存视图中的各个控件:

然后创建一个适配器类,实现 onCreateViewHolder、onBindViewHolder 和 getItemCount 三个方法:

-- -------------------- ---- -------
----- ------------------- --- ------ ----------- - -------------------------------------- -

    -------- --- -------------------------- ---------- --------- ----- -------------- -
        --- ---- - ----------------------------------------------------------------- ------- ------
        ------ --------------------
    -

    -------- --- ------------------------ --------------- --------- ---- -
        --- ---- - ---------------
        ----------------- - ----------
        ---------------------------------------------------------------
    -

    -------- --- --------------- --- -
        ------ ----------
    -
-

其中,onCreateViewHolder 方法用于创建 ViewHolder,onBindViewHolder 方法用于将数据绑定到视图中,getItemCount 方法用于返回数据源的总数。

设置布局管理器和适配器

最后,在 Activity 或 Fragment 中使用 RecyclerView,设置一个布局管理器和一个适配器。布局管理器可以用来管理列表条目的位置和大小,适配器则负责展示数据和更新视图。

-- -------------------- ---- -------
----- ------------ - ------------------- -

    -------- --- ---------------------------- -------- -
        ----------------------------------
        --------------------------------------

        --- ------------- - -------------------------
        -------------------------- - -------------

        --- ------- - ------------------
        -------------------- - -------
    -
-

至此,我们已经完成了 RecyclerView 的基本使用。

RecyclerView 的进阶使用

使用 DiffUtil

在实际开发中,我们经常需要对数据进行增删改查等操作,然后刷新列表以更新视图。RecyclerView 提供了默认的动画效果,但是如果数据量较大,这种操作可能会导致页面卡顿或ANR。

为了避免这种情况,谷歌提供了一个 DiffUtil 工具类,可以比较两个数据列表的差异,并以最小化的代价更新 RecyclerView 的数据和视图。DiffUtil 可以在后台线程中运行,不会影响主线程的流畅度,同时还可以提高列表的渲染效率。

使用 DiffUtil 需要完成以下步骤:

  • 定义一个数据类,将 Item 和它在列表中的位置组合成一个对象;
  • 构造一个 DiffUtil.Callback 对象,实现 getOldListSize、getNewListSize、areItemsTheSame 和 areContentsTheSame 四个方法;
  • 在适配器的 onBindViewHolder 方法中,将 DiffResult 中的差异应用到视图中。

以下是完整代码示例:

-- -------------------- ---- -------
---- ----- -------------------- ----- ----- --- --------- ----

----- ------------------------ --- -------- ----------- ------- --- -------- ----------- - ------------------- -

    -------- --- ----------------- --- -
        ------ ------------
    -

    -------- --- ----------------- --- -
        ------ ------------
    -

    -------- --- -------------------------------- ---- ---------------- ----- ------- -
        ------ ------------------------ -- ------------------------
    -

    -------- --- ----------------------------------- ---- ---------------- ----- ------- -
        ------ ------------------------ -- ------------------------
    -
-

----- -------------------- --- --------- ----------- - -------------------------------------- -

    -------- --- -------------------------- ---------- --------- ----- -------------- -
        --- ---- - ----------------------------------------------------------------- ------- ------
        ------ --------------------
    -

    -------- --- ------------------------ --------------- --------- ---- -
        --- ---- - -----------------------
        ----------------- - ----------
        ---------------------------------------------------------------
    -

    -------- --- --------------- --- -
        ------ -------------
    -

    --- --------------------- ----------- -
        --- ------- - ------------------- - ------ ---- -- ---------------------- ------ -
        --- ------- - ------------------- - ------ ---- -- ---------------------- ------ -
        --- ---------- - ------------------------------------------------- ----------
        -------- - --------
        ----------------------------------
    -
-

其中,ItemWithPosition 是一个包含 Item 和它在列表中位置的数据类。在适配器中,我们使用 updateItems 方法来更新数据,该方法首先将新旧数据列表转换为包含位置信息的 ItemWithPosition 列表,然后计算 DiffResult 并将它应用到适配器中。

实现拖拽排序

在某些应用中,我们需要实现拖拽排序的功能,即用户可以通过拖动列表条目来改变它们的位置。RecyclerView 提供了 ItemTouchHelper 类来帮助我们完成这个功能,它可以响应触摸事件,并管理相关的拖拽和移除操作。

使用 ItemTouchHelper 需要完成以下步骤:

  • 实现 ItemTouchHelper.Callback 类,并实现 onMove 和 onSwiped 两个方法;
  • 在适配器类中,定义一个 ItemTouchHelper 对象,并在 ViewHolder 构造函数中调用 ItemTouchHelper 的 attachToRecyclerView 方法将其绑定到 RecyclerView 上;
  • 在适配器的 onBindViewHolder 方法中,对被拖动的条目设置触摸事件,当用户拖动条目时,调用 ItemTouchHelper 的 startDrag 方法来开始拖动操作。

以下是完整代码示例:

-- -------------------- ---- -------
----- -------------------- --- ------ ----------- - --------------------------------------- ---------------------- -

    ------- --- --------------- - ----------------------------------------------

    -------- --- -------------------------- ---------- --------- ----- -------------- -
        --- ---- - ----------------------------------------------------------------- ------- ------
        ------ --------------------
    -

    -------- --- ------------------------ --------------- --------- ---- -
        --- ---- - ---------------
        ----------------- - ----------
        ---------------------------------------------------------------

        ---------------------------------- - -- ----- --
            -- ------------------- -- ------------------------ -
                ---------------------------------
            -
            -----
        -
    -

    -------- --- --------------- --- -
        ------ ----------
    -

    -------- --- ------------------------ ---- ----------- ---- -
        -- ------------- - ----------- -
            --- -- -- ------------ ----- ----------- -
                ----------------------- -- - - --
            -
        - ---- -
            --- -- -- ------------ ------ ---------- - -- -
                ----------------------- -- - - --
            -
        -
        ----------------------------- -----------
    -

    -------- --- ----------------------- ---- -
        ----- - ------------------- - ------ - -- ----- -- -------- -
        ---------------------------
    -

    ---- -
        --------------------------------------------------
    -
-

--------- ---------------------- -
    --- ------------------------ ---- ----------- ----
    --- ----------------------- ----
-

----- ------------------------------- --- -------- ----------------------- - -------------------------- -

    -------- --- ------------------------------ ------------- ----------- ------------------------- --- -
        --- --------- - ------------------ -- --------------------
        --- ---------- - --------------------- -- -------------------
        ------ ---------------------------- -----------
    -

    -------- --- -------------------- ------------- ----------- ------------------------ ------- ------------------------- ------- -
        ---------------------------------------------- -----------------------
        ------ ----
    -

    -------- --- -------------------- ------------------------ ---------- ---- -
        -------------------------------------------------
    -
-

其中,ItemTouchHelperAdapter 接口定义了两个方法,用于在适配器中响应拖拽和移除操作。在适配器中,我们使用 itemTouchHelper 对象来处理拖拽操作,在渲染每个条目时,为它添加一个触摸事件,当用户手指按下时,通过调用 startDrag 方法来开始拖动操作,从而触发 onItemMove 方法。在 ItemTouchHelperCallback 中,我们可以设置支持拖拽和滑动的方向,以及实现对应操作的逻辑。

总结

RecyclerView 是 Material Design 中使用广泛的、高度定制的列表控件。通过使用 RecyclerView,我们可以更好地管理大量数据、提供更佳的用户体验、提高应用性能和可维护性。

在本文中,我们详细介绍了 RecyclerView 的基本使用和进阶技巧,包括使用 DiffUtil 进行列表更新、实现拖拽排序等高级功能。我们相信,通过学习和实践,您可以掌握 RecyclerView 的精髓,并在自己的项目中应用这些技术。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6650dd1dd3423812e43ac9c3

纠错
反馈