Add margins to divider in RecyclerView
Asked Answered
D

9

42

i am building an android app which is using RecyclerView. I want to add dividers to RecyclerView, which I did using this code:

DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), linearLayoutManager.getOrientation());
recyclerView.addItemDecoration(dividerItemDecoration);

So far everything works fine. However, the divider is taking the size of full screen and I want to add margins to it. Is there any way that I can add margins to the divider using a method that will add some space to the rectangle drawn and not by creating a custom drawable shape with margins and add it to the RecyclerView?

Dilantin answered 9/1, 2017 at 11:26 Comment(2)
use custom dividerItemDecorationManganite
See this answer. By far the best and easiest solutionHeavyladen
B
16

Use this and customize according to your requirement.

public class DividerItemDecoration extends RecyclerView.ItemDecoration {

    private static final int[] ATTRS = new int[]{android.R.attr.listDivider};

    private Drawable divider;

    /**
     * Default divider will be used
     */
    public DividerItemDecoration(Context context) {
        final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
        divider = styledAttributes.getDrawable(0);
        styledAttributes.recycle();
    }

    /**
     * Custom divider will be used
     */
    public DividerItemDecoration(Context context, int resId) {
        divider = ContextCompat.getDrawable(context, resId);
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left = parent.getPaddingLeft();
        int right = 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 top = child.getBottom() + params.bottomMargin;
            int bottom = top + divider.getIntrinsicHeight();

            divider.setBounds(left, top, right, bottom);
            divider.draw(c);
        }
    }
}
Bullivant answered 9/1, 2017 at 11:30 Comment(1)
In my case it's only showing once after the last item.Blackstone
G
76

I think the most straightforward solution is to use the setDrawable method on the Decoration object and pass it an inset drawable with the inset values you want for the margins. Like so:

int[] ATTRS = new int[]{android.R.attr.listDivider};

TypedArray a = context.obtainStyledAttributes(ATTRS);
Drawable divider = a.getDrawable(0);
int inset = getResources().getDimensionPixelSize(R.dimen.your_margin_value);
InsetDrawable insetDivider = new InsetDrawable(divider, inset, 0, inset, 0);
a.recycle();

DividerItemDecoration itemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL);
itemDecoration.setDrawable(insetDivider);
recyclerView.addItemDecoration(itemDecoration);
Gault answered 27/12, 2017 at 8:41 Comment(8)
Genious! Thanks a lot!Draughtboard
Simply correct answer. Do not implement your own ItemDecoration if you can reuse and modify the existing one.Pleader
I'm getting OOM when calling obtainStyledAttributes. I'm using kotlinKuching
How could I set a height to this divider so it can be thicker?Madancy
@On_my_way_to_Dev_Life You would probably have to modify the source drawable to make it thicker.Gault
Best and minimal solution.Twitch
Great answer, but InsetDrawable requires API level 26+Trilby
It doesn't require min API 26, works just fineHelfand
U
21

shape.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#E6E7F0" />
    <size android:height="1dp" />
</shape>

layer.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@drawable/shape"
        android:left="16dp"
        android:right="16dp" />

</layer-list>

Code

val itemDecoration = DividerItemDecoration(context, DividerItemDecoration.VERTICAL)
itemDecoration.setDrawable(resources.getDrawable(R.drawable.layer, null))
recyclerView.addItemDecoration(itemDecoration)
Ursa answered 28/7, 2020 at 22:45 Comment(2)
This is the most simple solution to add margin of the divider in recycler view.Marylinmarylinda
no need for layer~ Just use inset:https://mcmap.net/q/27079/-how-to-indent-the-divider-in-a-linear-layout-recyclerview-ie-add-padding-margin-or-an-inset-only-to-the-itemdecorationPindling
B
16

Use this and customize according to your requirement.

public class DividerItemDecoration extends RecyclerView.ItemDecoration {

    private static final int[] ATTRS = new int[]{android.R.attr.listDivider};

    private Drawable divider;

    /**
     * Default divider will be used
     */
    public DividerItemDecoration(Context context) {
        final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
        divider = styledAttributes.getDrawable(0);
        styledAttributes.recycle();
    }

    /**
     * Custom divider will be used
     */
    public DividerItemDecoration(Context context, int resId) {
        divider = ContextCompat.getDrawable(context, resId);
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left = parent.getPaddingLeft();
        int right = 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 top = child.getBottom() + params.bottomMargin;
            int bottom = top + divider.getIntrinsicHeight();

            divider.setBounds(left, top, right, bottom);
            divider.draw(c);
        }
    }
}
Bullivant answered 9/1, 2017 at 11:30 Comment(1)
In my case it's only showing once after the last item.Blackstone
B
7

Elaborating on @SeptimusX75: if you (like me) prefer to do UI stuff in XML you can create an inset drawable file. You'll have to create a second XML file but since in return your code gets cleaner I say it's worth it :-).

[UPDATE] as user @Zhou Hongbo suggest in the comments, using only one XML file: divider.xml:

<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/divider_base"
    android:insetRight="20dp"
    android:insetLeft="20dp">

    <shape>
        <android:shape="rectangle">
        <size android:height="1dp" />
        <solid android:color="@color/dividerColor" />
    </shape>

</inset>

[OLD ANSWER]:

divider_base.xml (the actual divider):

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <size android:height="1dp" />
    <solid android:color="@color/dividerColor" />
</shape>

divider.xml (the inset):

<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/divider_base"
    android:insetRight="20dp"
    android:insetLeft="20dp">
</inset>
Buttonhole answered 28/9, 2020 at 10:24 Comment(1)
S
6

You can create your own item decoration for recycler view. Here is code for the same.

public class SimpleItemDecorator extends RecyclerView.ItemDecoration {

    int space;
    boolean isHorizontalLayout;
    public SimpleItemDecorator(int space) {
        this.space = space;
    }

    public SimpleItemDecorator(int space, boolean isHorizontalLayout) {
        this.space = space;
        this.isHorizontalLayout = isHorizontalLayout;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        if(isHorizontalLayout)
        {
            outRect.bottom=space;
            outRect.right=space;
            outRect.left=space;
            outRect.top=space;

        } else {
            outRect.bottom = space;
            if (parent.getChildAdapterPosition(view) == 0)
                outRect.top = space;
            else
                outRect.top = 0;

        }


    }
}

And to use it with your recyclerview you can do like this:

 recyclerView.addItemDecoration(new SimpleItemDecorator(5));
Spoke answered 9/1, 2017 at 11:30 Comment(2)
Ok...And how it will draw anything? There are no divider in that snippetJanenejanenna
@Janenejanenna it's adding space not drawing anything.Spoke
P
4

I found the best and simplest solution

<inset xmlns:android="http://schemas.android.com/apk/res/android"
       android:insetLeft="40dp"
       android:insetRight="40dp" >
    <shape>
        <size android:height="1dp"/>
        <solid android:color="@color/recyclerview_divider" />
    </shape>
</inset>

From: https://mcmap.net/q/27079/-how-to-indent-the-divider-in-a-linear-layout-recyclerview-ie-add-padding-margin-or-an-inset-only-to-the-itemdecoration

Pindling answered 1/3, 2022 at 11:48 Comment(0)
C
3

Same like @Vivek answer but in Kotlin and different params

class SimpleItemDecorator : RecyclerView.ItemDecoration {

    private var top_bottom: Int = 0
    private var left_right: Int = 0

    /**
     * @param top_bottom for top and bottom margin
     * @param left_right for left and right margin
     */
    constructor(top_bottom: Int, left_right: Int = 0) {
        this.top_bottom = top_bottom
        this.left_right = left_right
    }

    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
        super.getItemOffsets(outRect, view, parent, state)
        outRect.bottom = top_bottom
        outRect.top = top_bottom
        outRect.right = left_right
        outRect.left = left_right
    }
}
Cohen answered 21/5, 2018 at 6:29 Comment(0)
X
3

Here is a simple Kotlin code snippet to implement ItemDecoration with RecyclerView:

 recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
                override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
                    outRect.left = 20    // Left Margin.
                    outRect.right = 20   // Right Margin.
                    outRect.top = 16     // Top Margin.
                    outRect.bottom = 16  // Bottom Margin.
                }
            })

Explantation:- In the above example code, we are adding margins to each item of RecyclerView from all four directions.

Happy Coding...

Xerophilous answered 26/11, 2020 at 10:34 Comment(0)
P
0

Below is the code for divider in RecyclerView with left margin. Just paste the code in your OnCreate method of MainActivity.

class SimpleDividerItemDecoration extends RecyclerView.ItemDecoration {
    private Drawable mDivider;

    public SimpleDividerItemDecoration(Context context) {
        mDivider = context.getResources().getDrawable(R.drawable.divider);
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left = 250;
        int right = 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 top = child.getBottom() + params.bottomMargin;
            int bottom = top + mDivider.getIntrinsicHeight();

            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }
}
recyclerView.addItemDecoration(new SimpleDividerItemDecoration(
            getApplicationContext()));

Since, the divider.xml file will be missing from your drawable folder so below is the code that you have to paste on the divider layout after creating it on drawable folder.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

  <size
    android:width="1dp"
    android:height="1dp" />

  <solid android:color="@color/divider" />

</shape>
Piping answered 21/6, 2020 at 17:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.