Instantly share code, notes, and snippets.

Embed
What would you like to do?
An ItemDecoration that draws dividers between items. Pulled from Android support demos.
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private int mOrientation;
public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
@Override
public void onDraw(Canvas c, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}
@jpshelley

This comment has been minimized.

Copy link

jpshelley commented Oct 28, 2014

Why is onDraw and getItemOffsets deprecated now?

@akmalxxx

This comment has been minimized.

Copy link

akmalxxx commented Oct 29, 2014

That params has been deprecated and replaced with better params. Check my gist

https://gist.github.com/fatfingers/233abbae200b5e87297b

@IgorGanapolsky

This comment has been minimized.

Copy link

IgorGanapolsky commented Dec 22, 2014

What about onDrawOver(), is that a useful method compared to onDraw()?

@btdrucke

This comment has been minimized.

Copy link

btdrucke commented Dec 24, 2014

onDrawOver() will draw over the items in the list, onDraw() will draw under the items.

@polbins

This comment has been minimized.

Copy link

polbins commented Jan 6, 2015

@Leaking

This comment has been minimized.

Copy link

Leaking commented Mar 17, 2015

@btdrucke yep!

@yrom

This comment has been minimized.

Copy link

yrom commented Mar 18, 2015

@bejibx

This comment has been minimized.

Copy link

bejibx commented May 28, 2015

Hi! Consider using

RecyclerView.LayoutManager manager = parent.getLayoutManager();
final int left = manager.getDecoratedLeft(child);

to better support multiple ItemDecorations. For example if you add DividerItemDecoration and another ItemDecoration for spacing between items, dividers will be drawn at the end of each item instead of right between them because you are not consider offsets from other decorations.
drawVertical should look like this for example:

public void drawVertical(Canvas c, RecyclerView parent)
{
    RecyclerView.LayoutManager manager = parent.getLayoutManager();
    final int left = parent.getPaddingLeft();
    final int right = parent.getWidth() - parent.getPaddingRight();

    final int childCount = parent.getChildCount();
    for (int i = 0; i < childCount; i++)
    {
        final View child = parent.getChildAt(i);
        final int top = manager.getDecoratedBottom(child);
        final int bottom = top + mDivider.getIntrinsicHeight();
        mDivider.setBounds(left, top, right, bottom);
        mDivider.draw(c);
    }
}

Thank you for this gist!

@AviBenHamo

This comment has been minimized.

Copy link

AviBenHamo commented Jul 6, 2015

Grate work, simple and do what its should ,Thanks .

Based on your work i added a grid support , but i don't know what is the proper way to submit the change to the original git. Please check it out and marge it with the original for other to enjoy.
https://gist.github.com/AviBenHamo/638e48ca2a4525431656

P.s I did try this tutorial without any luck, Its written for a repository and not a Git!.
https://help.github.com/articles/creating-a-pull-request/

Thanks,
Avi.

@nkuznetsow

This comment has been minimized.

Copy link

nkuznetsow commented Jul 28, 2015

At line 58 possible to be used childCount-1 to avoid drawing divider after last item in list

@zeroarst

This comment has been minimized.

Copy link

zeroarst commented Sep 2, 2015

I wonder if it is a good idea to use Paint instead of bothering creating a drawable resource?
Any performance difference?

public DividerItemDecoration(Context context, int colorResId, int dividerWidthDimenResId) {
    mPaint = new Paint();
    mPaint.setColor(context.getResources().getColor(colorResId));
    mPaint.setStrokeWidth((int) context.getResources().getDimension(dividerWidthDimenResId));
}

@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
    int startX = parent.getPaddingLeft();
    int stopX = parent.getWidth() - parent.getPaddingRight();

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

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

        int y = child.getBottom() + params.bottomMargin;

        c.drawLine(startX, y, stopX, y, mPaint);
    }
}
@imSunny

This comment has been minimized.

Copy link

imSunny commented Oct 27, 2015

possible bug at line 79, it should be
final int right = left + mDivider.getIntrinsicWidth();

@adolfdsilva

This comment has been minimized.

Copy link

adolfdsilva commented Dec 18, 2015

    mDivider = a.getDrawable(0);

Returns null for 5.1.1

@Binghammer

This comment has been minimized.

Copy link

Binghammer commented Jan 6, 2016

Also adding:

 mDivider = a.getDrawable(0);

returns a null drawable.

@lengxuegang

This comment has been minimized.

Copy link

lengxuegang commented Jan 7, 2016

Also adding:
Line 79:

final int right = left + mDivider.getIntrinsicWidth();
@entrpn

This comment has been minimized.

Copy link

entrpn commented Jan 23, 2016

Thanks for this code. I am using it to set the divider in a PreferenceFragmentCompat. For a PreferenceFragmentCompat I had to make a change so not to display a divider line under the last element. To do this, I changed drawVertical() and drawHorizontal():

from:

for (int i = 0; i < childCount; i++) {

to:

for (int i = 0; i < childCount-1; i++) {

Thanks.

@dalewking

This comment has been minimized.

Copy link

dalewking commented Mar 8, 2016

You should not be looping over 0 to childCount (with or without the -1). You should loop from findFirstVisibleItemPosition() to findLastVisibleItemPosition(), checking them first for NO_POSITION. The last item check would then be whether the position is the last item from the adapter.

@mmanishh

This comment has been minimized.

Copy link

mmanishh commented Sep 13, 2016

Didn't work for android 5.0 +

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment