photo by Magda Ehlers

Step by Step: RecyclerView Swipe to Delete and Undo

Zachery Osborn
4 min readSep 12, 2018

--

Swipe to delete is a prevailing paradigm users are accustomed to on mobile platforms. Adding this functionally is a good way to get your app in line with modern design practices. While there are many libraries that will accomplish this for us, subsequently adding extra bulk to our code, implementing it ourselves is not that complicated. So, let’s get started.

To implement swipe to delete and undo in our RecyclerView we are going to need 3 key components:

  1. ItemTouchHelper: This attaches to the RecyclerView and watches for swipes.
  2. ItemTouchHelper.SimpleCallback: This is passed into ItemTouchHelper’s constructor and contains the code that will run once the item is swiped.
  3. Snackbar: This is triggered once an item is deleted and gives the user the option to undo the delete.

Step 1: ItemTouchHelper.SimpleCallback

First, let’s create a new class that extends ItemTouchHelper.SimpleCallback and write the constructor.

public class SwipeToDeleteCallback extends ItemTouchHelper.SimpleCallback {    private MyAdapter mAdapter;    public SwipeToDeleteCallback(MyAdapter adapter) {
super(0,ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
mAdapter = adapter;
}

The fist parameter in super adds support for dragging the RecyclerView item up or down. We don’t care about that hence the 0. The second parameter tells the ItemTouchHelper (that we will attach to the RecyclerView later) to pass our SimpleCallback information about left and right swipes. The constructor takes a reference to our adapter which we will use to call the deleteItem() function.

Next, we need to override onSwiped(). This is called when an item is swiped off the screen. You also need to override onMove() , but you can leave it as is.

@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
mAdapter.deleteItem(position);
}

The deleteItem() method does not exist yet but we’ll implement it later in the adapter.

That takes care of the core logic in the SimpleCallback, but we can make it look a little nicer.

Optional Step: Adding the background and Icon

To add our icon and background we just need to override onChildDraw(). This will draw our icon and background in the correct position as our RecyclerView item is swiped across the screen.

Since onChildDraw() is called multiple times per second, let’s try to keep the code as sparse as possible by adding the icon and background as member variables.

private Drawable icon;
private final ColorDrawable background;


public SwipeToDeleteCallback(TasksAdapter adapter) {
super(0,ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
mAdapter = adapter;
icon = ContextCompat.getDrawable(mAdapter.getContext(),
R.drawable.ic_delete_white_36);
background = new ColorDrawable(Color.RED);
}

Next, in onChildDraw() we need a reference to our ItemView which will be used to calculate the bounds for both the icon and background.

@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX,
dY, actionState, isCurrentlyActive);
View itemView = viewHolder.itemView;
int backgroundCornerOffset = 20;
}

backgroundCornerOffset is used to push the background behind the edge of the parent view so that it appears underneath the rounded corners (as seen in the .gif below). The larger the corner radius of your view, the larger backgroundCornerOffset should be.

Now, we add an if statement that covers the left, right, and no swipe cases. Then, set the bounds for our background in each case respectively and draw it onto the canvas.

To add the icon, define the bounds that are consistent across all swipe cases outside the if statement. Then, set the bounds for each case and draw it onto the canvas.

Alright, that does it for the ItemTouchHelper.SimpleCallback. Checkout the complete code here.

Step 2: Attach ItemTouchHelper to the Recyclerview

In your Activity or Fragment create a new ItemTouchHelper using our SwipeToDeleteCallback and attach it to the RecyclerView.

private void setUpRecyclerView() {
recyclerView.setAdapter(mAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
ItemTouchHelper itemTouchHelper = new
ItemTouchHelper(new SwipeToDeleteCallback(mAdapter));
itemTouchHelper.attachToRecyclerView(recyclerView);
}

Step 3: Deleting the item

In the adapter, we need to implement the deleteItem() method we called in SwipeToDeleteCallback earlier. In this method we will first save the removed item into a member variable to be used in case the user wants to undo the delete. We’ll also add a method call to show a Snackbar that we will implement in the next step. Finally, remove the item from our list and update the adapter.

public void deleteItem(int position) {
mRecentlyDeletedItem = mListItems.get(position);
mRecentlyDeletedItemPosition = position;
mListItems.remove(position);
notifyItemRemoved(position);
showUndoSnackbar();
}

Step 4: Undo Snackbar

Once an item is deleted our undo Snackbar should appear. We want the Snackbar’s action to add the recently removed item back to the list and update the adapter.

private void showUndoSnackbar() {
View view = mActivity.findViewById(R.id.coordinator_layout);
Snackbar snackbar = Snackbar.make(view, R.string.snack_bar_text,
Snackbar.LENGTH_LONG);
snackbar.setAction(R.string.snack_bar_undo, v -> undoDelete());
snackbar.show();
}

private void undoDelete() {
mListItems.add(mRecentlyDeletedItemPosition,
mRecentlyDeletedItem);
notifyItemInserted(mRecentlyDeletedItemPosition);
}

And… We’ve done it. Feel free to reach out if you have any questions. Happy coding.

--

--