
使用RecyclerView的Android中有许多教程,库以及拖放和滑动到关闭的实现 。 他们中的大多数人仍使用Roman Nurik开发的不赞成使用的View.OnDragListener和SwipeToDismiss方法。 尽管已经有了新的更有效的方法。 很少使用最新的API,通常依赖于GestureDetectors
和onInterceptTouchEvent
或其他更复杂的实现。 实际上,有一种非常简单的方法可以将这些功能添加到RecyclerView
。 这只需要一个类,它也是Android支持库的一部分。
ItemTouchHelper
ItemTouchHelper是一个功能强大的实用程序,可以处理将拖放 功能和滑动 清除功能添加到RecyclerView
。 该实用程序是RecyclerView.ItemDecoration的子类,可以轻松地将其添加到几乎所有现有的LayoutManager
和适配器中。 它还可以与元素动画配合使用,并能够将一种类型的元素拖放到列表中的另一处,甚至更多。 在本文中,我将演示ItemTouchHelper
的简单实现。 稍后,作为本系列文章的一部分,我们将扩大范围并考虑其他选择。
注意事项 是否想立即查看结果? 查看Github: Android-ItemTouchHelper-Demo 。 第一个提交与此文章有关。 演示.apk
文件可在此处下载。

客制化
首先,我们需要配置RecyclerView
。 如果尚未这样做,请将RecyclerView
依赖项添加到build.gradle
文件中。
compile 'com.android.support:recyclerview-v7:22.2.0'
ItemTouchHelper
几乎可以与所有RecyclerView.Adapter
和LayoutManager
,但是本文基于使用这些文件的示例。
使用ItemTouchHelper和ItemTouchHelper.Callback
要使用ItemTouchHelper
,您需要创建一个ItemTouchHelper.Callback 。 这是一个界面,可让您跟踪运动( eng。Move )和滑动( eng。Swipe )的动作。 此外,您可以在此处控制所选view
组件的状态并覆盖默认动画。 如果要使用基本实现SimpleCallback ,则可以使用一个帮助程序类。 但是,为了了解它在实践中是如何工作的,我们将自己做所有事情。
我们必须重新定义界面的主要功能,以包括拖放和滑动至关闭的基本功能:
getMovementFlags(RecyclerView, ViewHolder) onMove(RecyclerView, ViewHolder, ViewHolder) onSwiped(ViewHolder, int)
我们还将使用几种帮助方法:
isLongPressDragEnabled() isItemViewSwipeEnabled()
让我们一一考虑。
@Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(dragFlags, swipeFlags); }
ItemTouchHelper
可以轻松确定事件的方向。 您需要重写getMovementFlags()
方法以指示将支持哪些方向的拖放。 要创建返回标志,请使用辅助方法ItemTouchHelper.makeMovementFlags(int, int)
。 在此示例中,我们允许在两个方向上拖放。
@Override public boolean isLongPressDragEnabled() { return true; }
ItemTouchHelper
仅可用于不带滑动功能的拖放操作(反之亦然),因此必须准确指定应支持的功能。 长时间单击RecyclerView
元素后, isLongPressDragEnabled()
方法必须返回true
以支持拖放。 或者,您可以调用ItemTouchHelper.startDrag(RecyclerView.ViewHolder)
方法来开始手动拖动。 我们稍后将考虑该选项。
@Override public boolean isItemViewSwipeEnabled() { return true; }
要在触摸view
组件中的任何位置后启用鞭打,只需从isItemViewSwipeEnabled()
方法返回true
即可。 或者,您可以调用ItemTouchHelper.startSwipe(RecyclerView.ViewHolder)
方法来手动开始滑动。
需要以下两种方法onMove()
和onSwiped()
来通知您数据更新。 因此,首先我们将创建一个接口,以允许这些事件沿调用链传递。
ItemTouchHelperAdapter.java
public interface ItemTouchHelperAdapter { void onItemMove(int fromPosition, int toPosition); void onItemDismiss(int position); }
最简单的方法是让RecyclerListAdapter实现侦听器。
public class RecyclerListAdapter extends RecyclerView.Adapter<ItemViewHolder> implements ItemTouchHelperAdapter {
调用notifyItemRemoved()
和notifyItemMoved()
方法非常重要,这样适配器才能看到更改。 还应注意的是,每次view
组件移动到新索引时,我们都会更改元素的位置,而不是在移动的最后(“放下”事件) 。
现在,我们可以返回到创建SimpleItemTouchHelperCallback
,因为我们仍然需要重写onMove()
和onSwiped()
方法。 首先添加适配器的构造函数和字段:
private final ItemTouchHelperAdapter mAdapter; public SimpleItemTouchHelperCallback( ItemTouchHelperAdapter adapter) { mAdapter = adapter; }
然后重新定义其余事件并将其报告给适配器:
@Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); return true; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { mAdapter.onItemDismiss(viewHolder.getAdapterPosition()); }
结果, Callback
类应如下所示:
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback { private final ItemTouchHelperAdapter mAdapter; public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) { mAdapter = adapter; } @Override public boolean isLongPressDragEnabled() { return true; } @Override public boolean isItemViewSwipeEnabled() { return true; } @Override public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(dragFlags, swipeFlags); } @Override public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) { mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); return true; } @Override public void onSwiped(ViewHolder viewHolder, int direction) { mAdapter.onItemDismiss(viewHolder.getAdapterPosition()); } }
回调就绪后,我们可以创建一个ItemTouchHelper
并调用attachToRecyclerView(RecyclerView)
方法(例如,在MainFragment.java中 ):
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter); ItemTouchHelper touchHelper = new ItemTouchHelper(callback); touchHelper.attachToRecyclerView(recyclerView);
开始之后,您将获得如下内容:

结论
这是ItemTouchHelper
的最简化的实现。 但是,您可能会注意到,您不必使用第三方库在RecyclerView
实现标准的拖放和滑动到关闭操作 。 在下一部分中,我们将更加关注拖放时元素的外观。
源代码
我在GitHub上创建了一个项目,以演示本系列文章中介绍的内容: Android-ItemTouchHelper-Demo 。 第一次提交主要与此部分有关,而第二次 提交则有些许 。
→在RecyclerView中拖放。 第2部分:拖放控制器,网格和自定义动画