Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 34 You must be signed in to star a gist
  • Fork 14 You must be signed in to fork a gist
  • Save zokipirlo/82336d89249e05bba5aa to your computer and use it in GitHub Desktop.
Save zokipirlo/82336d89249e05bba5aa to your computer and use it in GitHub Desktop.
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;
}
}
@sylvia43
Copy link

Do you have a license on this?

@zokipirlo
Copy link
Author

No :)

@zokipirlo
Copy link
Author

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

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

@zokipirlo
Copy link
Author

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

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

@ClockerZadq
Copy link

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

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