Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
DividerItemDecoration. RecyclerView.ItemDecoration simple implementation

DividerItemDecoration

Simple RecyclerView ItemDecoration
Based on fatfingers implementation.

Fixed lapastillaroja implementation with correct first and last item handling.

Features

  • Can use any drawable as divider
  • Divider visible also at the beginning and end of the item's list (disabled by default)
  • Only works with LinearLayoutManager

New in this fork

  • Can use resource id as drawable
  • SpaceItemDecoration if you need only empty space between items

Example

Default android divider

mCategoryRecyclerView.addItemDecoration(
        new DividerItemDecoration(getActivity(), null));

Custom divider as drawable (deprecated) with first divider (before first element) and last divider (after last element)

mCategoryRecyclerView.addItemDecoration(
        new DividerItemDecoration(getActivity().getDrawable(R.drawable.ic_launcher),
                true, true));

Custom divider as resource id

mCategoryRecyclerView.addItemDecoration(
        new DividerItemDecoration(getActivity(), R.drawable.ic_launcher,
                true, true));

Space divider

mCategoryRecyclerView.addItemDecoration(
        new SpaceItemDecoration(getActivity(), R.dimen.list_space,
                true, true));
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private Drawable mDivider;
private boolean mShowFirstDivider = false;
private boolean mShowLastDivider = false;
int mOrientation = -1;
public DividerItemDecoration(Context context, AttributeSet attrs) {
final TypedArray a = context
.obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider});
mDivider = a.getDrawable(0);
a.recycle();
}
public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
boolean showLastDivider) {
this(context, attrs);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
public DividerItemDecoration(Context context, int resId) {
mDivider = ContextCompat.getDrawable(context, resId);
}
public DividerItemDecoration(Context context, int resId, boolean showFirstDivider,
boolean showLastDivider) {
this(context, resId);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
public DividerItemDecoration(Drawable divider) {
mDivider = divider;
}
public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
boolean showLastDivider) {
this(divider);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (mDivider == null) {
return;
}
int position = parent.getChildAdapterPosition(view);
if (position == RecyclerView.NO_POSITION || (position == 0 && !mShowFirstDivider)) {
return;
}
if (mOrientation == -1)
getOrientation(parent);
if (mOrientation == LinearLayoutManager.VERTICAL) {
outRect.top = mDivider.getIntrinsicHeight();
if (mShowLastDivider && position == (state.getItemCount() - 1)) {
outRect.bottom = outRect.top;
}
} else {
outRect.left = mDivider.getIntrinsicWidth();
if (mShowLastDivider && position == (state.getItemCount() - 1)) {
outRect.right = outRect.left;
}
}
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mDivider == null) {
super.onDrawOver(c, parent, state);
return;
}
// Initialization needed to avoid compiler warning
int left = 0, right = 0, top = 0, bottom = 0, size;
int orientation = mOrientation != -1 ? mOrientation : getOrientation(parent);
int childCount = parent.getChildCount();
if (orientation == LinearLayoutManager.VERTICAL) {
size = mDivider.getIntrinsicHeight();
left = parent.getPaddingLeft();
right = parent.getWidth() - parent.getPaddingRight();
} else { //horizontal
size = mDivider.getIntrinsicWidth();
top = parent.getPaddingTop();
bottom = parent.getHeight() - parent.getPaddingBottom();
}
for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL) {
top = child.getTop() - params.topMargin - size;
bottom = top + size;
} else { //horizontal
left = child.getLeft() - params.leftMargin;
right = left + size;
}
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
// show last divider
if (mShowLastDivider && childCount > 0) {
View child = parent.getChildAt(childCount - 1);
if (parent.getChildAdapterPosition(child) == (state.getItemCount() - 1)) {
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL) {
top = child.getBottom() + params.bottomMargin;
bottom = top + size;
} else { // horizontal
left = child.getRight() + params.rightMargin;
right = left + size;
}
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
}
private int getOrientation(RecyclerView parent) {
if (mOrientation == -1) {
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
mOrientation = layoutManager.getOrientation();
} else {
throw new IllegalStateException(
"DividerItemDecoration can only be used with a LinearLayoutManager.");
}
}
return mOrientation;
}
}
import android.content.Context;
import android.graphics.Rect;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;
public class SpaceItemDecoration extends RecyclerView.ItemDecoration
{
private final int mSpace;
private boolean mShowFirstDivider = false;
private boolean mShowLastDivider = false;
int mOrientation = -1;
public SpaceItemDecoration(Context context, AttributeSet attrs) {
mSpace = 0;
}
public SpaceItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
boolean showLastDivider) {
this(context, attrs);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
public SpaceItemDecoration(int spaceInPx)
{
mSpace = spaceInPx;
}
public SpaceItemDecoration(int spaceInPx, boolean showFirstDivider,
boolean showLastDivider)
{
this(spaceInPx);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
public SpaceItemDecoration(Context ctx, int resId)
{
mSpace = ctx.getResources().getDimensionPixelSize(resId);
}
public SpaceItemDecoration(Context ctx, int resId, boolean showFirstDivider,
boolean showLastDivider)
{
this(ctx, resId);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state)
{
if (mSpace == 0) {
return;
}
if (mOrientation == -1)
getOrientation(parent);
int position = parent.getChildAdapterPosition(view);
if (position == RecyclerView.NO_POSITION || (position == 0 && !mShowFirstDivider)) {
return;
}
if (mOrientation == LinearLayoutManager.VERTICAL) {
outRect.top = mSpace;
if (mShowLastDivider && position == (state.getItemCount() - 1)) {
outRect.bottom = outRect.top;
}
} else {
outRect.left = mSpace;
if (mShowLastDivider && position == (state.getItemCount() - 1)) {
outRect.right = outRect.left;
}
}
}
private int getOrientation(RecyclerView parent) {
if (mOrientation == -1) {
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
mOrientation = layoutManager.getOrientation();
} else {
throw new IllegalStateException(
"DividerItemDecoration can only be used with a LinearLayoutManager.");
}
}
return mOrientation;
}
}
@anubiann00b

This comment has been minimized.

Copy link

anubiann00b commented Aug 23, 2015

Do you have a license on this?

@zokipirlo

This comment has been minimized.

Copy link
Owner Author

zokipirlo commented Sep 1, 2015

No :)

@zokipirlo

This comment has been minimized.

Copy link
Owner Author

zokipirlo commented Sep 3, 2015

One note: If you add new elements to the end of the list, then there will be problem with last separator height.
I will try to fix that, but can't find any working solution yet.

@AriMeidan

This comment has been minimized.

Copy link

AriMeidan commented Sep 7, 2015

Hi, I get an error that this method does not exist:
getChildAdapterPosition

@zokipirlo

This comment has been minimized.

Copy link
Owner Author

zokipirlo commented Sep 8, 2015

Strange. What version of recyclerview do you have in gradle?
I'm working on 22.2.1 (compile 'com.android.support:recyclerview-v7:22.2.1') right now.

@andreasnilsson

This comment has been minimized.

Copy link

andreasnilsson commented Oct 9, 2015

Why are you not following the java/android style guideline for SpaceItemDecoration?

@ClockerZadq

This comment has been minimized.

Copy link

ClockerZadq commented Feb 24, 2016

Good stuff - but it doesn't work with xml shapes how come? The new vector assets seem to work well with this. Add shape please!!

@brandlee

This comment has been minimized.

Copy link

brandlee commented Aug 25, 2016

Hi,I've got a really weird problem,when I code this mLayoutManager.setReverseLayout(true); for my LinearLayoutManager, the SpaceItemDecoration won't work in Second item!

@sune6

This comment has been minimized.

Copy link

sune6 commented Oct 11, 2018

Use DividerItemDecoration and set RecyclerView android:scrollbars="vertical" will cause scrollbar sectioned, onDrawOver shoud be onDraw

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.