Upcoming and OnDemand Webinars View full list

A View Divided: Adding Dividers to Your RecyclerView with ItemDecoration

David Greenhalgh

At Google I/O 2014, Google unveiled RecyclerView, a successor to ListView. RecyclerView sought to strip away much of the cruft that slowed down ListView, and in doing so, shipped without some of the conveniences we’d gotten used to. We’ve discussed how to responsibly add some of that functionality back in previous blog posts, and today we’ll continue with a look at list dividers.

One common task that isn’t as convenient in RecyclerView is the addition of dividers or offsets between list items, but you can fortunately create your own dividers with ItemDecoration.

ItemDecoration

RecyclerView.ItemDecoration is a tool used to decorate the children of a RecyclerView. RecyclerView is a ViewGroup, with each of its children representing an item in a list. With ItemDecoration you can easily modify the appearance of these child views.

For example, let’s add dividers to a RecyclerView using a LinearLayoutManager, oriented vertically. In order to do so, we’ll subclass ItemDecoration, giving our new class a constructor that takes in a divider to be drawn between list items.

public class DividerItemDecoration extends RecyclerView.ItemDecoration {

    private Drawable mDivider;

    public DividerItemDecoration(Drawable divider) {
        mDivider = divider;
    }
...

ItemDecoration features three methods for us to override, but we’ll only need two: getItemOffsets and onDraw.

First, getItemOffsets. We need to provide offsets between list items so that we’re not drawing dividers on top of our child views. getItemOffsets is called for each child of your RecyclerView.

@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
    super.getItemOffsets(outRect, view, parent, state);

    if (parent.getChildAdapterPosition(view) == 0) {
        return;
    }

    outRect.top = mDivider.getIntrinsicHeight();
}

In getItemOffsets, we’re changing the shape of the Rect outRect, which determines the amount of padding on each side of the the list item. By default, this padding is 0. Here, we change the top field of outRect to the height of our divider so that it has room to be drawn without overlapping any other views.

Note that we skip this action for the first item in the list so that we don’t draw an offset above the RecyclerView.

Next, in onDraw, we determine the bounds of our divider and draw it onto the RecyclerView. onDraw is called just once.

@Override
public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
    int dividerLeft = parent.getPaddingLeft();
    int dividerRight = parent.getWidth() - parent.getPaddingRight();

    int childCount = parent.getChildCount();
    for (int i = 0; i < childCount - 1; i++) {
        View child = parent.getChildAt(i);

        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

        int dividerTop = child.getBottom() + params.bottomMargin;
        int dividerBottom = dividerTop + mDivider.getIntrinsicHeight();

        mDivider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom);
        mDivider.draw(canvas);
    }
}

We first calculate the left and right bounds of the parent RecyclerView, as they will be the left and right bounds of our divider between each child view. We then have to calculate the location of the top and bottom of each divider, as they’re unique for each child view.

Once we have these bounds calculated, we’re able to set the bounds of each divider and draw it on the screen.

Usage

Adding an ItemDecoration to your RecyclerView is fairly straightforward. Using the example above, get an instance of your new DividerItemDecoration, passing in the Drawable you’d like to use as a divider (in this case, dividerDrawable).

RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecoration(dividerDrawable);
recyclerView.addItemDecoration(dividerItemDecoration);

You can even add multiple ItemDecorations to the same RecyclerView. They tend to play nicely, but they’ll draw on top of each other in the order in which they are added. You can change this drawing priority by passing in an index to your addItemDecoration call:

int decorPriorityIndex = 0;
recyclerView.addItemDecoration(dividerItemDecoration, decorPriorityIndex);

You can also remove an ItemDecoration at will:

recyclerView.removeItemDecoration(dividerItemDecoration);

SimpleItemDecoration

ItemDecorations are a quick, flexible way to customize your RecyclerView. I’ve provided six ItemDecoration implementations wrapped in a library that I’ve creatively named SimpleItemDecoration.

SimpleItemDecoration in Action

Let’s use SimpleItemDecoration to add a divider to a RecyclerView with a LinearLayoutManager.

Drawable dividerDrawable = ContextCompat.getDrawable(this, R.drawable.divider);

recyclerView.addItemDecoration(new DividerItemDecoration(dividerDrawable));

We get a reference to a divider to use as a Drawable and pass it to the constructor of our DividerItemDecoration. Then we simply attach the new DividerItemDecoration to our RecyclerView via RecyclerView#addItemDecoration.

If this looks eerily similar to the ItemDecoration example above, that’s because it is. The difference here is that you don’t have to supply the ItemDecoration implementations—I’ve taken care of that.

So far, I’ve written solutions for the following six ItemDecoration implementations:

Let me know if you think of other uses for ItemDecoration!

Not Happy with Your Current App, or Digital Product?

Submit your event

Let's Discuss Your Project

Let's Discuss Your Project