Material Design 的很大一部分是用户与应用程序的视觉元素进行交互的方式。因此,除了点击和长按之外,今天制作精良的 android 应用程序有望处理更复杂的触摸手势,例如滑动和拖动。如果应用程序使用列表来显示其数据,这一点尤其重要。
通过使用recyclerview
小部件和其他一些 Android Jetpack 组件,您可以在应用程序中处理各种与列表相关的滑动手势。此外,只需几行代码,您就可以将 Material Motion 动画与这些手势相关联。
在本教程中,我将向您展示如何将一些常见的滑动手势以及直观的动画添加到您的列表中。
先决条件
为了能够充分利用本教程,您需要:
Android Studio 3.2.1 或更高版本
运行 Android api level 23 或更高版本的手机或平板电脑
1.创建列表
为了使本教程简短,让我们使用 Android Studio 中可用的模板之一来生成我们的列表。
首先启动 Android Studio 并创建一个新项目。在项目创建向导中,确保选择Empty Activity 选项。
在这个项目中,我们将使用 Android Jetpack 而不是 Support 库。因此,一旦项目生成,请转到Refactor > Migrate to AndroidX。出现提示时,按迁移 按钮。
接下来,要向项目添加列表,请转到File > New > Fragment > Fragment (List)。在弹出的对话框中,继续并按完成 按钮,而不对默认值进行任何更改。
此时,Android Studio 将创建一个包含完全配置的 RecyclerView
小部件的新片段。它还将生成虚拟数据以显示在小部件内。但是,您仍然需要手动将片段添加到您的主要活动中。
为此,首先将OnListFragmentInteractionListener
接口添加到您的主活动并实现它包含的唯一方法。
override fun onListFragmentInteraction( item: DummyContent.DummyItem?) { // leave empty }
<fragment>
接下来,通过将以下标记添加到activity_main.xml 文件,将片段嵌入到活动中:
<fragment android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/list_fragment" android:name="com.tutsplus.rvswipes.ItemFragment" />
此时,如果您运行您的应用程序,您应该能够看到如下所示的列表:
2.添加滑动删除手势
使用ItemTouchHelper
该类,您可以快速将滑动和拖动手势添加到任何 RecyclerView
小部件。该类还提供了在检测到有效手势时自动运行的默认动画。
该类ItemTouchHelper
需要一个抽象类的实例 才能检测和处理手势。尽管您可以直接使用它,但使用一个名为的包装类会更容易 。它也是抽象的,但是您将拥有更少的方法来覆盖。ItemTouchHelper.callback
SimpleCallback
SimpleCallback
在类的onCreateView()
方法中创建类的新实例ItemFragment
。作为其构造函数的参数,您必须传递您希望它处理的滑动方向。现在,传递RIGHT
给它,以便它处理向右滑动的手势。
val myCallback = object: ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) { // More code here }
该类有两个必须重写的抽象方法:onMove()
检测拖动的onSwiped()
方法和检测滑动的方法。因为我们今天不会处理任何拖动手势,所以请确保您false
在 onMove()
方法内返回。
override fun onMove( recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder ): Boolean = false override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { // More code here }
在该onSwiped()
方法中,您可以使用该 属性来确定被滑动的列表项的索引。因为我们现在正在实现滑动删除手势,所以将索引传递给 虚拟列表的方法以删除项目。adapterposition
removeAt()
DummyContent.ITEMS.removeAt(viewHolder.adapterPosition)
此外,您必须将相同的索引传递给小部件适配器的notifyItemRemoved()
方法, RecyclerView
以确保不再呈现该项目。这样做还会运行默认的项目移除动画。
adapter?.notifyItemRemoved(viewHolder.adapterPosition)
至此,SimpleCallback
对象已准备就绪。您现在需要做的就是 ItemTouchHelper
使用它创建一个对象并将RecyclerView
小部件附加到它。
val myHelper = ItemTouchHelper(myCallback) myHelper.attachToRecyclerView(this)
如果您现在运行该应用程序,您将能够将项目从列表中滑出。
3.显示背景视图
尽管滑动移除手势非常直观,但一些用户可能不确定他们执行该手势时会发生什么。因此,Material Design 指南说,手势还必须逐步显示隐藏在项目后面的视图,这清楚地表明接下来会发生什么。通常,背景视图只是一个显示垃圾箱的图标。
要将垃圾桶图标添加到您的项目,请转到File > New > Vector Asset 并选择名为delete的图标。
您现在可以通过调用该 方法在您的kotlin代码中获取对图标的引用。getDrawable()
因此,将以下行添加到类的onCreateView()
方法中 ItemFragment
:
val trashBinIcon = resources.getDrawable( R.drawable.ic_delete_black_24dp, null )
在列表项后面显示视图有点复杂,因为您需要手动绘制它,同时还要确保它的边界与逐渐显示的区域的边界相匹配。
覆盖onChildDraw()
您的SimpleCallback
实现方法以开始绘图。
override fun onChildDraw( c: canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean ) { // More code here super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive) }
在上面的代码中,onChildDraw()
对超类的方法的调用很重要。没有它,您的列表项在滑动时将不会移动。
因为我们只处理向右滑动手势,所以背景视图左上角和左下角的 X 坐标将始终为零。另一方面,右上角和右下角的 X 坐标应该等于参数dX
,该参数指示用户移动了多少列表项。
要确定所有角的 Y 坐标,您必须使用对象 内部存在的视图之一的top
和 属性 。bottom
viewHolder
使用所有这些坐标,您现在可以定义一个矩形剪辑区域。以下代码向您展示了如何使用对象的clipRect()
方法Canvas
来做到这一点:
c.clipRect(0f, viewHolder.itemView.top.toFloat(), dX, viewHolder.itemView.bottom.toFloat())
尽管您不必这样做,但最好通过给它一个背景颜色来使剪辑区域可见。以下是如何使用该drawColor()
方法在滑动距离较小时使剪辑区域变为灰色,在滑动距离较大时使剪辑区域变为红色。
if(dX < width / 3) c.drawColor(Color.GRAY) else c.drawColor(Color.RED)
您现在必须指定垃圾桶图标的边界。这些边界必须包含与列表项中显示的文本相匹配的边距。要确定以像素为单位的边距值,请使用该getDimension()
方法并传递text_margin
给它。
val textMargin = resources.getDimension(R.dimen.text_margin) .roundToInt()
您可以重复使用剪辑区域左上角的坐标作为图标左上角的坐标。但是,它们必须被 textMargin
. 要确定其右下角的坐标,请使用其固有宽度和高度。就是这样:
trashBinIcon.bounds = Rect( textMargin, viewHolder.itemView.top + textMargin, textMargin + trashBinIcon.intrinsicWidth, viewHolder.itemView.top + trashBinIcon.intrinsicHeight + textMargin )
draw()
最后,通过调用其方法绘制图标。
trashBinIcon.draw(c)
如果您再次运行该应用程序,您应该能够在滑动删除列表项时看到该图标。
4.添加滑动刷新手势
滑动刷新手势,也称为拉动刷新手势,如今变得如此流行,以至于 Android Jetpack 为其提供了一个专用组件。它被称为 SwipeRefreshLayout
,它允许您快速将手势与任何 RecyclerView
、ListView
或GridView
小部件相关联。
要在您的小部件中支持滑动刷新手势RecyclerView
,您必须使其成为SwipeRefreshLayout
小部件的子级。所以打开fragment_item_list.xml 文件,给它添加一个 标签,然后在 里面<SwipeRefreshLayout>
移动标签。<RecyclerView>
完成此操作后,文件的内容应如下所示:
<?xml version="1.0" encoding="utf-8"?> <androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="https://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/list" android:name="com.tutsplus.rvswipes.ItemFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginLeft="16dp" android:layout_marginRight="16dp"/> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
列表片段假定RecyclerView
小部件是其布局的根元素。因为这不再是真的,你需要对类的 onCreateView()
方法做一些改变ItemFragment
。首先,用以下代码替换方法的第一行,它会膨胀布局:
val srLayout: SwipeRefreshLayout = inflater.inflate( R.layout.fragment_item_list, container, false ) as SwipeRefreshLayout val view = srLayout.findViewById<RecyclerView>(R.id.list)
接下来,更改方法的最后一行以返回SwipeRefreshLayout
小部件而不是RecyclerView
小部件。
return srLayout
如果您现在尝试运行该应用程序,您将能够执行垂直滑动手势并获得视觉反馈。不过,列表的内容不会改变。要真正刷新列表,您必须将OnRefreshListener
对象与SwipeRefreshLayout
小部件相关联。
srLayout.setOnRefreshListener { // 这里有更多代码 }
在监听器内部,您可以根据自己的需求自由修改列表显示的数据。现在,因为我们正在使用虚拟数据,所以我们只需清空虚拟项目列表并重新加载 25 个新的虚拟项目。以下代码向您展示了如何执行此操作:
f
更新数据后,一定要记得调用notifydataSetChanged()
方法让adapter
小RecyclerView
部件知道它必须重绘列表。
view.adapter?.notifyDataSetChanged()
默认情况下,只要用户执行滑动刷新手势, SwipeRefreshLayout
小部件就会显示动画进度指示器。因此,在更新列表后,您必须记住通过将 isRefreshing
小部件的属性设置为 false 来删除指示器。
srLayout.isRefreshing = false
如果您现在运行该应用程序,删除一些列表项,然后执行滑动刷新手势,您将看到列表自行重置。
结论
Material Design 已经存在了几年,现在大多数用户都希望你能处理它提到的许多手势。幸运的是,这样做并不需要太多的努力。在本教程中,您学习了如何实现两个非常常见的滑动手势。您还学习了如何逐步显示隐藏在正在滑动的列表项后面的视图。