Part 3: RecyclerView from zero to hero

Alfredo Cerezo Luna
6 min readFeb 27, 2018

The devil is in the details: customise your items’ background.

What you will find here:

In the last two post: Part 1- First things first: implementing a basic RecyclerView and Part 2 — Giving it functionalities: swipe and drag & drop we covered how to implement a basic RecyclerView and how we can add swipe and drag & drop, so now is turn to make our RecyclerView a little bit better.
We are going to learn how to paint a nice background and an icon when we swipe an item, this way we give to the user a hint that something is about to happen while he/she swipes an item.

The basics

Remember our ItemTouchHelper.Callback() implementation from the previous post? In case you don’t:

The ItemTouchHelper.Callback() does lots of things, and one of them is to control how the system paints the view that we are interacting with, the following method does that job:

public void onChildDraw(Canvas c, RecyclerView recyclerView,ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive)

By default, the ItemTouchHelper moves the item applying a translation leaving an empty background, but if we override this method we can customize this behaviour and paint a custom one using the Canvas c, we don’t need to worry about anything else, the method itself is going to take care of how to paint the background according to the Android version.

The method onChildDraw is called iteratively by the RecyclerView updating the dx and dy values, which specify the amount of space the ItemView has been moved.

So let’s do it!

First of all I am going to assume that you got a basic idea on how a Canvas works, if you don’t, don’t panic, we are going to make it easy (at least for painting something basic), once you finish this post you will just need to care about which icon do you want to draw and the color for your background.

We are going to create a utility class that is going to all this work painting a background following the next steps:

  • Getting the resources, namely: background color and icon.
  • Drawing the background.
  • Drawing the icon.

Getting the resources

This step is optional, we can ignore it and hardcode everything, or we can follow a more generic approach in which we define externally the id of the resources, this way we can reuse this code in other projects, and even better, we are going to decouple our drawing logic from our resource creation logic giving us the chance to extend it in a future.

For this purpose let’s encapsulate our resources inside a private class that will help us to keep this information along the drawing process:

And now lets define a couple of helper methods to create objects of this type

We want to provide two kind of feedback to the users: one to show that an element has reached the threshold distance and the action is triggered, and another one to show that the distance is not enough yet.

To know when the item has reached the threshold distance we use this helper function that takes the width of the view and the distance already swiped by the item, and checks if this is bigger or smaller than a threshold value.

The isolation of this logic is important, this way we can change this condition by something more complex, and more important, we can reuse this logic somewhere else in de code.

Drawing the background

To do this we are going to use a Paint, a Paint basically is a container that holds the style and color to be used to draw inside a canvas.

We want to paint a rectangle that fills the empty space left by the swiped item, and this rectangle is going to be specified using a RectF, another Android class that defines a geometric shape specifying its bounds.

Once we have created both objects we only need to tell the canvas to paint in itself a RectF following the rules specified by the Paint

In Android the coordinate system for graphics has its origin in the (0,0), this origin is located in the upper left corner, therefore if we move the item to the bottom of the screen we are moving along the positive Y-axe, and if we move the item to the right, we are moving along the positive X-axe

Let’s analyse deeper how we define the RectF: as you can see, the upper and bottom bounds are always the same, they correspond with the bounds of the view that we are swiping.

The right bound correspond with the right bound of the swiped view (we are swiping to the left), and the left bound corresponds also with the right bound of the swiped view, so that we have an invisible rectangle of with 0 at the beginning. But if we modify the view swiping it, it’s right bound is going to be moved also, and the rectangle we are painting grows as long as we keep on doing the gesture, since the left bound of the background stays with it, leaving an empty space where the background it’s going to be painted.

Drawing the icon

This is the most delicate part because we need to locate the icon inside the space occupied by the background painted in the previous step.

To paint a Drawable over a canvas we need to define the container rectangle, in this case another Rect, the Drawable will be deformed to fill the space defined by this Rect, so we need to be very careful to not change the original shape an ratio of the raw icon.
Our goal is to paint and move this icon while we swipe the recyclerview item, so lets define and modify these 4 bounds of this Rect to achieve that.

Top and bottom: we want to allocate our icon in the middle of the vertical space left by the swiped item, so we define a bottom and top margin, so let’s calculate how much space we need to leave on the top and bottom.

Left: the left bound of the Rect icon’s container will move with the view being swiped, this way we give the perception to the user that the icon is being animated, how can we know this value? easy, we got the value dx(negative) which measures the amount of space the view has been moved and we also have the position of the item’s right bound (remember that we are just swiping to the left).

Right: intuitively you may think that this bound is somehow related with the right bound of the item, but nothing further from the reality, the truth is that this value is going to be the previously calculated left bound, plus the width of the icon.

Resulting in this code

And now we just tell the icon to draw itself over the canvas inside the Rectthat we just defined icon.draw(canvas)

Everything together

So now to draw our icon we just need to put everything together in the following way:

An call this last method from our ItemTouchHelperCallback, more precisely from the onChildDraw() method

And this is it! We have isolated all the complexity in just one method call!

SwipeBackgroundHelper.paintDrawCommandToStart(canvas, viewItem, R.drawable.ic_trash, dX)

Now we should have something like this:

Background and icon

Summary

Plenty of things on this post, we modified our code to paint a background while we swipe an item in a way that its color changes when the action its triggered, and we also added a nice icon which moves together with the item showing to our users which action are they triggering with the action.

To do this, we splited everything in three phases: one to get all the resources, one to paint the background and another one to paint the icon.

Continue reading

Part 3b: RecyclerView from zero to hero — Let’s make it shine: expanding circle background effect!

Code

Thanks for reading! Any comment or feedback is welcome.

--

--