在RecyclerView中拖放。 第1部分:ItemTouchHelper

在RecyclerView中拖放。第1部分:ItemTouchHelper


使用RecyclerView的Android中有许多教程,库以及拖放滑动到关闭的实现 。 他们中的大多数人仍使用Roman Nurik开发的不赞成使用的View.OnDragListenerSwipeToDismiss方法。 尽管已经有了新的更有效的方法。 很少使用最新的API,通常依赖于GestureDetectorsonInterceptTouchEvent或其他更复杂的实现。 实际上,有一种非常简单的方法可以将这些功能添加到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.AdapterLayoutManager ,但是本文基于使用这些文件的示例。


使用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 { // ...   [](https://gist.github.com/iPaulPro/2216ea5e14818056cfcc#file-recyclerlistadapter-java) @Override public void onItemDismiss(int position) { mItems.remove(position); notifyItemRemoved(position); } @Override public boolean onItemMove(int fromPosition, int toPosition) { if (fromPosition < toPosition) { for (int i = fromPosition; i < toPosition; i++) { Collections.swap(mItems, i, i + 1); } } else { for (int i = fromPosition; i > toPosition; i--) { Collections.swap(mItems, i, i - 1); } } notifyItemMoved(fromPosition, toPosition); return true; } 

调用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部分:拖放控制器,网格和自定义动画

Source: https://habr.com/ru/post/zh-CN427681/


All Articles