Decorating RecyclerView (with GridLayoutManager) to display divider between items

android-recyclerview gridlayoutmanager divider line
gridlayoutmanager itemdecoration
how to display divider border between gridview items in android
recyclerview divider item decoration height
recyclerview divider padding
grid layout manager recyclerview columns
how to remove divider line in recyclerview android
android recyclerview gridlayoutmanager column width

What's the best and easiest way to decorate RecyclerView to have such look & feel?

The main challenge here is having dividers only between items, but not between items and left/right borders of screen.

Any ideas?

I don't know why do you need that, but this UI is quite easy to implement with RecyclerView decorator.

<!--Integer Value that number of column in RecyclerView-->
<integer name="photo_list_preview_columns">3</integer>

<!-- inter spacing between RecyclerView's Item-->
<dimen name="photos_list_spacing">10dp</dimen>

You can change photo_list_preview_columns and photos_list_spacing according to your needs.

mRecylerView.addItemDecoration(new ItemDecorationAlbumColumns(
    getResources().getDimensionPixelSize(R.dimen.photos_list_spacing), 
    getResources().getInteger(R.integer.photo_list_preview_columns)));

and decorator (needs some refatoring)

import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;

public class ItemDecorationAlbumColumns extends RecyclerView.ItemDecoration {

    private int mSizeGridSpacingPx;
    private int mGridSize;

    private boolean mNeedLeftSpacing = false;

    public ItemDecorationAlbumColumns(int gridSpacingPx, int gridSize) {
        mSizeGridSpacingPx = gridSpacingPx;
        mGridSize = gridSize;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int frameWidth = (int) ((parent.getWidth() - (float) mSizeGridSpacingPx * (mGridSize - 1)) / mGridSize);
        int padding = parent.getWidth() / mGridSize - frameWidth;
        int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewAdapterPosition();
        if (itemPosition < mGridSize) {
            outRect.top = 0;
        } else {
            outRect.top = mSizeGridSpacingPx;
        }
        if (itemPosition % mGridSize == 0) {
            outRect.left = 0;
            outRect.right = padding;
            mNeedLeftSpacing = true;
        } else if ((itemPosition + 1) % mGridSize == 0) {
            mNeedLeftSpacing = false;
            outRect.right = 0;
            outRect.left = padding;
        } else if (mNeedLeftSpacing) {
            mNeedLeftSpacing = false;
            outRect.left = mSizeGridSpacingPx - padding;
            if ((itemPosition + 2) % mGridSize == 0) {
                outRect.right = mSizeGridSpacingPx - padding;
            } else {
                outRect.right = mSizeGridSpacingPx / 2;
            }
        } else if ((itemPosition + 2) % mGridSize == 0) {
            mNeedLeftSpacing = false;
            outRect.left = mSizeGridSpacingPx / 2;
            outRect.right = mSizeGridSpacingPx - padding;
        } else {
            mNeedLeftSpacing = false;
            outRect.left = mSizeGridSpacingPx / 2;
            outRect.right = mSizeGridSpacingPx / 2;
        }
        outRect.bottom = 0;
    }
}

Adding dividers between recyclerview items for GridLayoutManager, Adding dividers between recyclerview items for GridLayoutManager Then, it won't show the divider for last item, and it will work well for lines, you can set this item decoration to your recyclerview, and get the inner borders. L ist is a common component that every Android developer implements in its routine/daily basis. At some point, we need to add a divider between items and/or just adjust the margin for cards to be

Here's a simpler and more user-friendly implementation:

public class MediaSpaceDecoration extends RecyclerView.ItemDecoration {
    private final int spacing;
    private final List<Integer> allowedViewTypes = Arrays.asList(
            R.layout.item_image,
            R.layout.item_blur);

    public MediaSpaceDecoration(int spacing) {
        this.spacing = spacing;
    }

    @Override
    public void getItemOffsets(Rect outRect,
                               View view,
                               RecyclerView parent,
                               RecyclerView.State state) {
        final int position = parent.getChildAdapterPosition(view);
        if (!isMedia(parent, position)) {
            return;
        }

        final int totalSpanCount = getTotalSpanCount(parent);
        int spanSize = getItemSpanSize(parent, position);
        if (totalSpanCount == spanSize) {
            return;
        }

        outRect.top = isInTheFirstRow(position, totalSpanCount) ? 0 : spacing;
        outRect.left = isFirstInRow(position, totalSpanCount) ? 0 : spacing / 2;
        outRect.right = isLastInRow(position, totalSpanCount) ? 0 : spacing / 2;
        outRect.bottom = 0; // don't need
    }

    private boolean isInTheFirstRow(int position, int spanCount) {
        return position < spanCount;
    }

    private boolean isFirstInRow(int position, int spanCount) {
        return position % spanCount == 0;
    }

    private boolean isLastInRow(int position, int spanCount) {
        return isFirstInRow(position + 1, spanCount);
    }

    private int getTotalSpanCount(RecyclerView parent) {
        final RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        return layoutManager instanceof GridLayoutManager
            ? ((GridLayoutManager) layoutManager).getSpanCount()
            : 1;
    }

    private int getItemSpanSize(RecyclerView parent, int position) {
        final RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        return layoutManager instanceof GridLayoutManager
            ? ((GridLayoutManager) layoutManager).getSpanSizeLookup().getSpanSize(position)
            : 1;
    }

    private boolean isMedia(RecyclerView parent, int viewPosition) {
        final RecyclerView.Adapter adapter = parent.getAdapter();
        final int viewType = adapter.getItemViewType(viewPosition);
        return allowedViewTypes.contains(viewType);
    }
}

I also check before setting the outRect because I have various spanSizes for each viewType and I need to add an extra middle-space only for allowedViewTypes. You can easily remove that verification and the code would be even simpler. It looks like this for me:

Simple Item Decoration by Big Nerd Ranch, View the Project on GitHub. Overview. Simple Item Decoration includes six ItemDecorations: start, end, and divider decoration for use with LinearLayoutManager; and start, end, and divider decoration for use with GridLayoutManager. Instantiate one or more of these decoration and add to a standard RecyclerView. DividerItemDecoration is a RecyclerView.ItemDecoration that can be used as a divider between items of a LinearLayoutManager. It supports both HORIZONTAL and VERTICAL orientations.

You may got your answer but i'm still posting my solution that can help others. This can be used for vertical, horizontal lists or grid views by passing the orientation.

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.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

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;
    public static final int GRID = 2;

    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 && orientation != GRID) {
            throw new IllegalArgumentException("invalid orientation");
        }
        mOrientation = orientation;
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == VERTICAL_LIST) {
            drawVertical(c, parent);
        } else if(mOrientation == HORIZONTAL_LIST){
            drawHorizontal(c, parent);
        } else {
            drawVertical(c, parent);
            drawHorizontal(c, parent);
        }
    }

    public void drawVertical(Canvas c, RecyclerView parent) {
        if (parent.getChildCount() == 0) return;

        final int left = parent.getPaddingLeft();
        final int right = parent.getWidth() - parent.getPaddingRight();

        final View child = parent.getChildAt(0);
        if (child.getHeight() == 0) return;

        final RecyclerView.LayoutParams params =
                (RecyclerView.LayoutParams) child.getLayoutParams();
        int top = child.getBottom() + params.bottomMargin + mDivider.getIntrinsicHeight();
        int bottom = top + mDivider.getIntrinsicHeight();

        final int parentBottom = parent.getHeight() - parent.getPaddingBottom();
        while (bottom < parentBottom) {
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);

            top += mDivider.getIntrinsicHeight() + params.topMargin + child.getHeight() + params.bottomMargin + mDivider.getIntrinsicHeight();
            bottom = top + mDivider.getIntrinsicHeight();
        }
    }

    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 + mDivider.getIntrinsicHeight();
            final int right = left + mDivider.getIntrinsicWidth();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == VERTICAL_LIST) {
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        } else if(mOrientation == HORIZONTAL_LIST) {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
        } else {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight());
        }
    }
}

Android RecyclerView GridLayout DividerItemDecoration. Based on , Determines the size and location of offsets between items in the parent. * RecyclerView. @param view The child view to be decorated with an offset. * @​param Adds horizontal dividers to a RecyclerView with a GridLayoutManager or its. Divider ItemDecoration draws divider separating two items in RecyclerView. It works for both horizontal and vertical orientations with LinearLayoutManager. Divider ItemDecoration draws a line between items using Paint. You need to pass context, divider color and line width as parameter to the constructor of the item decoration.

One more simple solution that worked for me. Hope it can be useful.

class GridItemDecorator(val context: Context, private val spacingDp: Int, private val mGridSize: Int) : RecyclerView.ItemDecoration() {

    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {

        val resources = context.resources
        val spacingPx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, spacingDp.toFloat(), resources.displayMetrics)

        val bit = if (spacingPx > mGridSize) Math.round(spacingPx / mGridSize) else 1
        val itemPosition = (view.layoutParams as RecyclerView.LayoutParams).viewAdapterPosition

        outRect.top = if (itemPosition < mGridSize) 0 else  bit * mGridSize
        outRect.bottom = 0

        val rowPosition = itemPosition % mGridSize
        outRect.left = rowPosition * bit
        outRect.right = (mGridSize - rowPosition - 1) * bit

    }
}

A View Divided: Adding Dividers to Your RecyclerView with , Decorating RecyclerView (with GridLayoutManager) to display divider between items The main challenge here is having dividers only between items, but not  DividerItemDecoration is a RecyclerView.ItemDecoration that can be used as a divider between items of a LinearLayoutManager. It supports both HORIZONTAL and VERTICAL orientations. Usage:

  @BindingAdapter({"bind:adapter"})
    public static void bind(RecyclerView view, RecyclerView.Adapter<BaseViewHolder> adapter) {
        view.setLayoutManager(new GridLayoutManager(view.getContext(), 3));
        view.addItemDecoration(new SpacesItemDecorationGrid(view.getContext(), 4, 3));
        view.setItemAnimator(new DefaultItemAnimator());
        view.setAdapter(adapter);
    }


public class SpacesItemDecorationGrid extends RecyclerView.ItemDecoration {

    private int mSizeGridSpacingPx;
    private int mGridSize;
    private boolean mNeedLeftSpacing = false;

    /**
     * @param gridSpacingPx
     * @param gridSize
     */
    SpacesItemDecorationGrid(Context context, int gridSpacingPx, int gridSize) {
        mSizeGridSpacingPx = (int) Util.convertDpToPixel(gridSpacingPx, context);
        mGridSize = gridSize;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int frameWidth = (int) ((parent.getWidth() - (float) mSizeGridSpacingPx * (mGridSize - 1)) / mGridSize);
        int padding = parent.getWidth() / mGridSize - frameWidth;
        int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewAdapterPosition();
        int itemCount = parent.getAdapter().getItemCount() - mGridSize;


   /*     if (itemPosition < mGridSize) {
            outRect.top = mSizeGridSpacingPx;
        } else {
                   outRect.top = mSizeGridSpacingPx;
        }*/
        outRect.top = mSizeGridSpacingPx;
        if (itemPosition % mGridSize == 0) {
            outRect.left = mSizeGridSpacingPx;
            outRect.right = padding;
            mNeedLeftSpacing = true;
        } else if ((itemPosition + 1) % mGridSize == 0) {
            mNeedLeftSpacing = false;
            outRect.right = mSizeGridSpacingPx;
            outRect.left = padding;
        } else if (mNeedLeftSpacing) {
            mNeedLeftSpacing = false;
            outRect.left = mSizeGridSpacingPx - padding;
            if ((itemPosition + 2) % mGridSize == 0) {
                outRect.right = mSizeGridSpacingPx - padding;
            } else {
                outRect.right = mSizeGridSpacingPx / 2;
            }
        } else if ((itemPosition + 2) % mGridSize == 0) {
            mNeedLeftSpacing = false;
            outRect.left = mSizeGridSpacingPx / 2;
            outRect.right = mSizeGridSpacingPx - padding;
        } else {
            mNeedLeftSpacing = false;
            outRect.left = mSizeGridSpacingPx / 2;
            outRect.right = mSizeGridSpacingPx / 2;
        }
        if (itemPosition > itemCount) {
            outRect.bottom = mSizeGridSpacingPx;
        } else {
            outRect.bottom = 0;
        }

    }

}

RecyclerView Decorations, A View Divided: Adding Dividers to Your RecyclerView with ItemDecoration RecyclerView is the addition of dividers or offsets between list items, but you can ItemDecoration is a tool used to decorate the children of a RecyclerView . GridLayoutManager, interior dividers · GridLayoutManager, top offset  I am developing an android application where I am using RecyclerView. I need to add a divider in RecyclerView. I tried to add - recyclerView.addItemDecoration(new DividerItemDecoration(getAc

RecyclerView Decorations / How to add dividers using and , decoration, the item decoration to add to the RecyclerView This will draw a line at the bottom of every view but the last to act as a separator between items. GridLayoutManager(getActivity(), 2); ItemOffsetDecoration itemDecoration = new​  With RecyclerView you can display a table of data, display items in a grid or if you want you can also do a Staggered layout as Pinterest does it with every item being a different size. Consider the following case where a new item is added to the list, pushing some other items outside the visible area. getItemCount returns the total number of

Using the RecyclerView, RecyclerView Decorations / How to add dividers using and DividerItemDecoration ItemDecoration that can be used as a divider between items. ItemOffsetDecoration for GridLayoutManager in RecycleView 108 Device Display Metrics. The following is the step-by-step simple solution if you want the equal spacing around items and equal item sizes. ItemOffsetDecoration public class ItemOffsetDecoration extends RecyclerView.ItemDecoration { private int mItemOffset; public ItemOffsetDecoration(int itemOffset) { mItemOffset = itemOffset; } public ItemOffsetDecoration(@NonNull Context context, @DimenRes int itemOffsetId) { this

The RecyclerView is a ViewGroup that renders any adapter-based view in a similar Manual Item Decoration - ListView has the android:divider property for easy we can choose between LinearLayoutManager , GridLayoutManager , and  Decorator. In Android, when you work with RecyclerViews, the standard way of working with paddings and margins is to work with fixed dimensions inside of the layout files. While this works for many applications, sometimes the margins inside the layout files shouldn't be applied in every screen. Decorator is a library that helps creating composable margins and dividers in RecyclerViews.

Comments
  • see developer.android.com/reference/android/support/v7/widget/…, android.view.View, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State)
  • @pskink I see that it's necessary to create/reuse some kind of item decoration. The question is about concrete solution.
  • @pskink what's correct way to determine wether item has right / left neighbours or not within getItemOffsets method?
  • RecyclerView.getChildPosition(View child) gives you the item position, and the position determines where the item is lay out on the RecyclerView
  • @pskink how to understand is it around border or not (in general case) ?
  • Thanks, Dmitry! Works like a charm!
  • @AlexKorovyansky the same UI but with Load more items howthis can be achieved ?
  • This is a good start but this draw lines underneath the bottom row when items are animating (i.e., notifyItemChanged called)
  • If I could I would just come and hug you bro. This is the thing I was looking for. Thanks
  • What is mean of mNeedLeftSpacing state variable? Does it relay on call ordering?