Updated date:

How to Enable Swipe for Actions in Android RecyclerView

Mohammad Yasir is a Physics graduate from the University of Delhi and currently enrolled in the Master's Programme at IIT.

Introduction

RecyclerView is one of the most incredible and versatile classes in the Android SDK that can serve as a modern and memory-efficient alternative to ListView and GridView instances.

In this article, we will discuss a quick and simple way of implementing swipe functionality in your Android Apps that utilize the RecyclerView class. While a basic application of the RecyclerView class is quite rudimentary, this article assumes that you have a fundamental understanding of Android App development using Java and are comfortable with RecyclerViews.

What We Are Trying to Achieve

In itself, the RecyclerView class is nothing more than a module for your ViewHolder instances to reside in. It can handle no other workload. While this makes sense in various ways, it also means that several basic functionalities are missing in the RecyclerView by default.

Luckily, the introduction of the ItemTouchHelper and SimpleCallback classesallows you to quickly implement this functionality quite easily. Here is what I am talking about, implemented beautifully by Microsoft Outlook:

MS Outlook provides an option to swipe for a quick action on your emails.

MS Outlook provides an option to swipe for a quick action on your emails.

How Do We Make it Happen?

The open-source nature of Android OS and its limitless popularity gives it a significant advantage over its competitors in terms of flexibility and versatility. Originally, the idea was to pick an open-source library from GitHub that included these functionalities in a custom RecyclerView class. However, that method is now deprecated.

The ItemTouchHelper and the SimpleCallback classes, as previously mentioned, provide a few methods that we can override and implement complex swiping and dragging & dropping gestures in our RecyclerView instances. That is what we shall be doing in this article. The screenshot given below shows what the end result will look like:

The end result. Swiping right

The end result. Swiping right

The Process

The simplest and the fastest way of including swipe functionality in your RecyclerView instances involves extending the SimpleCallback class, overriding the getSwipeDirs(), onMove(), and onChildDrawOver() methods, and performing the following steps:

  • In the getSwipeDirs() method, return either 0 to prevent a user from swiping on, say, a child view that is being used as a header, or return with a call to super.getSwipeDirs().
  • In the onMove() method, return a boolean value indicating whether you wish to enable RecyclerView item dragging. I have returned false and you will need to write your own implementation if your case involves dragging as well.
  • Write the logic for drawing the swipe background and icon in onChildDrawOver().

Once you have performed the aforementioned steps, we will discuss how to use an instance of the class you have created.

Let Us Get Started

Start by creating a new java class in your project and naming it RecyclerSwipeHelper.java. This class will extend SimpleCallback and override its constructor, as well as the three methods I mentioned above.

The first step is to create a few global variables that will come in handy later on. Take a look below:

//You can set this tag in your adapter's onAttachViewHolder() method if you wish to prevent swiping on a particular child view. Then use an if condition in the getSwipeDirs() method and return 0 if the tag equals @link TAG_NO_SWIPE
public static final String TAG_NO_SWIPE = "don't swipe this item";
    
private final int intrinsicWidth;
private final int intrinsicHeight;
private final int swipeLeftColor;
private final int swipeRightColor;

private final Paint clearPaint;
private final Drawable swipeRightIcon;
private final Drawable swipeLeftIcon;
private final ColorDrawable background = new ColorDrawable();

The Constructor

public RecyclerSwipeHelper(@ColorInt int swipeRightColor, @ColorInt int swipeLeftColor, @DrawableRes int swipeRightIconResource, @DrawableRes int swipeLeftIconResource, Context context) {

	//The LEFT|RIGHT are tags from the ItemTouchHelper class that inform the system about swipe directions. The first paramter informs the system about dragging directions, which are 0 to prevent dragging.
	super(0, LEFT|RIGHT);
	
	//here, you can initialize the icons that will be displayed upon swiping. That is what the parameters are for. You can customize them as per your needs. As an example, here is the swipeRightIcon initialized using the ContextCompat class.
	//You can similarly initialize swipeLeftIcon. 
	this.swipeRightIcon = ContextCompat.getDrawable(context, swipeRightIconResource);

	//initialize a few global variables for later use.
	//the Paint instance will be used to clear the canvas if the swiping is canceled by the user.
	clearPaint = new Paint();
	clearPaint.setXfermode(new PorterDuffXfermode(CLEAR));

	// these are int parameters and represent the intrinsic height and width of your icons. These icons are aptly named swipeRightIcon and swipeLeftIcon. 
	intrinsicHeight = swipeRightIcon.getIntrinsicHeight();
	intrinsicWidth = swipeRightIcon.getIntrinsicWidth();
}

The Brains of the Operation

The onChildDrawOver() method is where all the magic happens. In this method, you will perform the following steps:

  1. Get the child view height using the ViewHolder provided in the parameters.
  2. Check if swipe was canceled by the user. If yes, clear the canvas, call super, and return.
  3. Else, check whether the swipe was done towards the right or towards the left. Appropriately, draw the correct icon and background.

This is how we make that happen:

//get item height and check if cancelled
View itemView = viewHolder.itemView;
int itemHeight = itemView.getBottom() - itemView.getTop();
boolean isCanceled = (dX == 0f) && !isCurrentlyActive;

if (isCanceled) {
	clearCanvas(c, itemView.getRight() + dX, itemView.getTop(), itemView.getRight(), itemView.getBottom());
	super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, false);
	return;
}

if (dX < 0); //swipe left logic;
else; //swipe right logic

While the code shown above is pretty self-explanatory, you will notice a strange method that is called in case the isCanceled variable is evaluated to be true.

It is absolutely essential for you to call this method since it will clear our canvas and show the original RecyclerView item. This is how you make it happen. Notice how we have used the clearPaint instance that we created in the beginning to erase any signs of the icons or backgrounds that might have been drawn before the swipe was canceled:

private void clearCanvas(Canvas c, float left, float top, float right, float bottom) {
	if(c != null) c.drawRect(left, top, right, bottom, clearPaint);
}

Drawing the Icons and Backgrounds

By default, the ItemTouchHelper class will do nothing apart from swipe your ViewHolder in the direction allowed. You will need to handle drawing the background and icons on your own. Regardless of direction, the logic behind that is quite similar.

  1. Draw the background color using the ColorDrawable we initialized in the beginning.
  2. Calculate the position of the drawable. The logic will change slightly with the direction.
  3. Draw the icon.

Take a look below:

//This sample is for the swipe left logic, i.e. it will go into the if block of your code. 

background.setColor(swipeLeftColor);
background.setBounds((int) (itemView.getRight() + dX), itemView.getTop(), itemView.getRight(), itemView.getBottom());
background.draw(c);

int itemTop = itemView.getTop() + (itemHeight - intrinsicHeight) / 2;
int itemMargin = (itemHeight - intrinsicHeight) / 2;
int itemLeft = itemView.getRight() - itemMargin - intrinsicWidth;
int itemRight = itemView.getRight() - itemMargin;
int itemBottom = itemTop + intrinsicHeight;

swipeLeftIcon.setBounds(itemLeft, itemTop, itemRight, itemBottom);
swipeLeftIcon.draw(c);

Once again, you can see how simple it is to draw the icons. Note that since we are we are using a canvas to draw the icon directly, we will need to calculate its left, right, top, and bottom attributes. They will be used to place the drawable correctly.

What about swiping right?

Easy. Just make a few adjustments as given below:

background.setColor(swipeRightColor);

//Notice how we are using the getLeft() method here instead of getRight().
background.setBounds((int) (itemView.getLeft() + dX), itemView.getTop(), itemView.getLeft(), itemView.getBottom());
background.draw(c);

int itemTop = itemView.getTop() + (itemHeight - intrinsicHeight) / 2;
int itemMargin = (itemHeight - intrinsicHeight) / 2;
int itemLeft = itemView.getLeft() + itemMargin;
int itemRight = itemView.getLeft() + itemMargin + intrinsicWidth;
int itemBottom = itemTop + intrinsicHeight;

swipeRightIcon.setBounds(itemLeft, itemTop, itemRight, itemBottom);
swipeRightIcon.draw(c);

Notice how the bounds for the background as well as the logic to calculate itemLeft and itemRight has changed. Without it, the icon would get drawn in weird places and would even end up being invisible.

NOTE:

Don't forget to call super after your logic is complete, as given below:

super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);

Finishing up

And that's it! Before you know it, your RecyclerSwipeHelper class is complete and you are ready to use it and get swiping. You will again notice the remarkable ease with which you can make that happen. Take a look at the example given below:

RecyclerSwipeHelper mRecyclerSwipeHelper = new RecyclerSwipeHelper(swipeRightColor, swipeLeftColor, swipeRightIconResource, swipeLeftIconResource, context) {
	@Override
	public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
		
		//calling the notifyItemChanged() method is absolutely essential to redraw the RecyclerView item and remove the icons we had drawn.
		mAdapter.notifyItemChanged(viewHolder.getBindingAdapterPosition());

		if (direction == ItemTouchHelper.LEFT)
		//handle left swipe
		
		else 
		//handle right swipe
      
    	}
};
ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(mRecyclerSwipeHelper);
mItemTouchHelper.attachToRecyclerView(mRecyclerView);

Complete Code Sample

The RecyclerSwipeHelper I use for my projects is available on my GitHub gist. You can directly import that into your project if you do not want to go through the hassle of creating your own implementation.

Psst! If you import my class into your project, you'll be able to get your hands on a cool fade in and fade out animation on your icons while swiping. Just don't forget to credit me if you do, as mentioned below:

RecyclerSwipeHelper created by Mohammad Yasir.


Do leave your valuable feedback and share any tips you think can be helpful.

© 2021 Mohammad Yasir

Related Articles