There are many educational materials, libraries and examples of drag & drop and swipe-to-dismiss implementation in Android using RecyclerView. Most of them still use the outdated View.OnDragListener and the SwipeToDismiss approach developed by Roman Nurik. Although new and more effective methods are already available. Very few use the latest API, often relying on GestureDetectors
and onInterceptTouchEvent
or on other more complex implementations. In fact, there is a very simple way to add these functions to RecyclerView
. This requires only one class, which is also part of the Android Support Library.
ItemTouchHelper is a powerful utility that takes care of everything that needs to be done to add the drag & drop and swipe-to-dismiss functions to RecyclerView
. This utility is a subclass of RecyclerView.ItemDecoration , making it easy to add to almost any existing LayoutManager
and adapter. It also works with animation elements and provides the ability to drag items of one type to another place in the list and much more. In this article, I will demonstrate a simple implementation of the ItemTouchHelper
. Later, in this series of articles, we will expand the scope and consider other possibilities.
Note. Want to see the result right away? Check out Github: Android ItemTouchHelper-Demo . The first commit is related to this article. A demo .apk
file can be downloaded here .
First we need to configure RecyclerView
. If you have not done so yet, add the RecyclerView
dependency to your build.gradle
file.
compile 'com.android.support:recyclerview-v7:22.2.0'
ItemTouchHelper
will work with almost any RecyclerView.Adapter
and LayoutManager
, but this article is based on examples using these files .
To use ItemTouchHelper
, you need to create an ItemTouchHelper.Callback . This is an interface that allows you to track movement ( eng. Move) and swipe ( eng. Swipe) actions. In addition, here you can control the state of the selected view
component and override the default animation. There is a helper class that you can use if you want to use the basic implementation, SimpleCallback . But in order to understand how this works in practice, we will do everything on our own.
The main interface functions that we must override in order to enable basic drag & drop and swipe-to-dismiss functionality :
getMovementFlags(RecyclerView, ViewHolder) onMove(RecyclerView, ViewHolder, ViewHolder) onSwiped(ViewHolder, int)
We will also use several helper methods:
isLongPressDragEnabled() isItemViewSwipeEnabled()
Consider them one by one.
@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
makes it easy to determine the direction of an event. You need to override the getMovementFlags()
method to specify which directions to drag and drop will be supported. To create returned flags, use the ItemTouchHelper.makeMovementFlags(int, int)
helper method. In this example, we allow dragging and brushing in both directions.
@Override public boolean isLongPressDragEnabled() { return true; }
ItemTouchHelper
can only be used for dragging without the swipe function (or vice versa), so you should specify exactly which functions should be supported. The isLongPressDragEnabled()
method must return true
to support dragging after a long click on the RecyclerView
element. Alternatively, you can call the ItemTouchHelper.startDrag(RecyclerView.ViewHolder)
method to start dragging manually. Consider this option later.
@Override public boolean isItemViewSwipeEnabled() { return true; }
To allow swipe after touching anywhere within the view
component, simply return true
from the isItemViewSwipeEnabled()
method. Alternatively, you can call the ItemTouchHelper.startSwipe(RecyclerView.ViewHolder)
method to start the manual swipe.
The following two methods, onMove()
and onSwiped()
, are needed in order to notify you of data updates. So, first we will create an interface that allows you to pass these events along a call chain.
public interface ItemTouchHelperAdapter { void onItemMove(int fromPosition, int toPosition); void onItemDismiss(int position); }
The easiest way to do this is to have RecyclerListAdapter implement the listener.
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; }
It is very important to call the notifyItemRemoved()
and notifyItemMoved()
methods so that the adapter can see the changes. It should also be noted that we change the position of the element each time the view
component moves to a new index, and not at the very end of the move (the “drop” event) .
Now we can go back to creating the SimpleItemTouchHelperCallback
, since we still need to override the onMove()
and onSwiped()
methods. First add a constructor and a field for the adapter:
private final ItemTouchHelperAdapter mAdapter; public SimpleItemTouchHelperCallback( ItemTouchHelperAdapter adapter) { mAdapter = adapter; }
Then redefine the remaining events and report this to the 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()); }
As a result, the Callback
class should look something like this:
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()); } }
When the callback is ready, we can create an ItemTouchHelper
and call the attachToRecyclerView(RecyclerView)
method (for example, in MainFragment.java ):
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter); ItemTouchHelper touchHelper = new ItemTouchHelper(callback); touchHelper.attachToRecyclerView(recyclerView);
After the launch should get something like this:
This is the most simplified implementation of ItemTouchHelper
. However, you may notice that you do not need to use a third-party library to implement standard drag & drop and swipe-to-dismiss actions in RecyclerView
. In the next part, we will pay more attention to the appearance of the elements at the time of dragging or swiping.
I created a project on GitHub to demonstrate what is described in this series of articles: Android-ItemTouchHelper-Demo . The first commit mainly relates to this part and a little to the second .
→ Drag and Swipe in RecyclerView. Part 2: Drag and Drop Controllers, Grid, and Custom Animations
Source: https://habr.com/ru/post/427681/
All Articles