Moving and swiping with RecyclerView

Moving and swiping with RecyclerView

It's been a long time RecylcerView is around. Most devs are already familiar with the basics of this useful class. We know how to create Adapters, ViewHolders, adding and removing items. But what about a bit more advanced things such as swiping items and moving items (drag-and-drop) inside the list?

The good news is that RecyclerView makes these "advanced" things quite easy. The bad news is that it's a bit confusing to figure it out in the docs. My aim here is, now that I did figure it out, to put it all together hoping that I will save some time for the next developer looking how to do it.

Requirements

I assume that you already have your RecyclerView set up and an Adapter that handles the managing of your data. Pretty much, you have your list visible and functional (follow this guide to set up your list).

The SimpleCallback

This is where you define what events you want to react to (e.g. swiping and/or drag-and-drop) and what you want to do when these events happen.

class MyAdapter : RecyclerView.Adapter<ViewHolder>() {
    private var tasks: List<Task> = arrayListOf()

    [...]

    private val simpleItemTouchCallback =
        object : ItemTouchHelper.SimpleCallback(
           // [1] The allowed directions for moving (drag-and-drop) items
           UP or DOWN or START or END, 
           // [2] The allowed directions for swiping items
           0) {
            override fun onMove(
                recyclerView: RecyclerView, 
                viewHolder: RecyclerView.ViewHolder, 
                target: RecyclerView.ViewHolder): Boolean {
                    // [3] Do something when an item is moved
                    
                    val adapter = recyclerView.adapter
                    val from = viewHolder.adapterPosition
                    val to = target.adapterPosition

                    // [4] Keep up-to-date the underlying data set
                    Collections.swap(tasks, from, to)
                    // [5] Tell the adapter to switch the 2 items
                    adapter?.notifyItemMoved(from, to)

                    return true
            }

            override fun onSwiped(
                viewHolder: RecyclerView.ViewHolder, 
                direction: Int) {
                    // [6] Do something when an item is swiped
            }
            
            override fun clearView(
                recyclerView: RecyclerView, 
                viewHolder: RecyclerView.ViewHolder) {
                    super.clearView(recyclerView, viewHolder);
                    // [7] Do something when the interaction with an item 
                    // is complete
            }
}

This SimpleCallback is an abstract class and you need an object to extend it.  In its constructor, you define which directions you are allowing items to move (in [1]) or swipe (in [2]).

Then, there are dedicated methods that are called when an item is moved ([3]) or swiped ([6]).  Notice that the switching of the items in the underlying list, is your responsibility ([4]) and for the default item switching animation to happen, you need to let the adapter know about the move ([5]).

Notice that in the case of moving items in the list, the method is called as soon as an item switches position with another one. This means that if you have a list with 5 items, and you move the last item to the first position, this method will be called 5 times while you drag your item to the top.

If you want to make an operation after the drop has happened (e.g. the entire move item interaction is completed and you need to save the new order of your underlying model to storage), you need to do it in the clearView method ([7]).

The attaching

This is the easy part. After you define what will happen in the events you are interested in, you just need to wrap it in an ItemTouchHelper and attach it to your RecyclerView.

ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(recyclerView)

Happy moving and swiping items around in your RecyclerViews!

Show Comments