Skip to content

Instantly share code, notes, and snippets.

@alexfu
Last active February 9, 2023 05:09
Star You must be signed in to star a gist
Save alexfu/0f464fc3742f134ccd1e to your computer and use it in GitHub Desktop.
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
Copy link

Why is onDraw and getItemOffsets deprecated now?

@akmalxxx
Copy link

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

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

@IgorGanapolsky
Copy link

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

@btdrucke
Copy link

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

@polbins
Copy link

polbins commented Jan 6, 2015

@Leaking
Copy link

Leaking commented Mar 17, 2015

@btdrucke yep!

@yrom
Copy link

yrom commented Mar 18, 2015

@bejibx
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
Copy link

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
Copy link

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

@zeroarst
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
Copy link

imSunny commented Oct 27, 2015

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

@adolfdsilva
Copy link

    mDivider = a.getDrawable(0);

Returns null for 5.1.1

@Binghammer
Copy link

Also adding:

 mDivider = a.getDrawable(0);

returns a null drawable.

@xuegl
Copy link

xuegl commented Jan 7, 2016

Also adding:
Line 79:

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

@entrpn
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
Copy link

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
Copy link

Didn't work for android 5.0 +

@pavelsust
Copy link

how i can increase divider width and height???????

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