Adding dividers in GridLayout RecyclerView
Asked Answered
C

2

1

I tried adding horizontal dividers to my GridLayout RecyclerView. But for some reason, the dividers didn't show up.

As an alternative, I used the addItemDecoration method with 2 parameters, where the second parameter is the index after which to add the ItemDecoration.

RecyclerView r = (RecyclerView) findViewById(R.id.recycler_view);
r.setAdapter(new AppAdapter(this, fetchData());
r.setLayoutManager(new GridLayoutManager(this, 5));
r.addItemDecoration(new DividerItemDecoration(this, GridLayoutManager.HORIZONTAL), 2);

And it force closed with the following exception:

Caused by: java.lang.IndexOutOfBoundsException: Index: 2, Size: 0

What does this Size signify? Why is it zero?

Could it be because I am using this RecyclerView in an Activity instead of a Fragment?

P.S.: There is no issue with the adapter; it is not empty.

Cadre answered 23/2, 2017 at 21:1 Comment(4)
When you do addItemDecoration(new DividerItemDecoration(this, GridLayoutManager.HORIZONTAL), 2); you are trying to add the divider at index 2, but the error tells you that this is out of bounds because the number of children in the RecyclerView is 0 (it is empty). Get rid of that line, and let me know if anything is shown.Conyers
The adapter or the recyclerView is not empty. A proper list is displayed without writing that line.Cadre
How many items are in your list? If there are less than 10 (aka less than 2 rows), then this might be the issueConyers
More than 50 items.Cadre
C
2

The error is because you are telling the RecyclerView to draw your decoration number 2, without telling it what to draw number 1 and 0.

(It's implemented as an ArrayList of decorations to draw in order, and it's trying to insert your decoration at index 2 into an empty ArrayList - hence OutOfBounds!)

Edit: Here's a working example:

I've tested this code, and it works fine if you make the following changes:

1- Use the single parameter version of the method, the indexed version will give out of bounds as explained (you need to start indexing from 0).

r.addItemDecoration(new SpacesItemDecoration(10));

2- Use the following ItemDecoration class:

public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
    private int space;

    public SpacesItemDecoration(int space) {
        this.space = space;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        outRect.bottom = space;
    }
}

This will give you space only at the bottom (for horizontal dividers).

3 - Change your RecyclerView layout so that the background colour of your RecyclerView is the colour you want the dividers to be:

<android.support.v7.widget.RecyclerView
                                                    android:layout_width="match_parent"
                                                    android:layout_height="match_parent"
                                                    android:background="#000000"> # DIVIDER COLOUR

            </android.support.v7.widget.RecyclerView>

4- Change your item layout so that the background of the root item is not transparent, and not the same colour as the RecyclerView (obviously)

<RelativeLayout
            android:id="@+id/item_root"
            android:background="#cc00cc"
          android:layout_width="match_parent"
          android:layout_height="wrap_content">

The reason nothing was showing before may have been because the RecyclerView background and the item background were the same, so the divider wasn't visible.

This method works with both Linear and Grid Layout Managers.

I hope this (finally!) helps :)

Conyers answered 23/2, 2017 at 22:11 Comment(10)
I have tried using a custom item decoration class already. The IndexOutOfBounds exception still keeps popping up.Cadre
Do you mean you get the error when using LinearLayoutManager?Conyers
I meant, I created a custom ItemDecoration class specific to GridLayoutManager and it still failed the same way.Cadre
I just finished trying out your suggestion of changing the layoutmanager to LinearLayoutManager. And addItemDecoration() with 2 parameters still force closes the app with the same error. And addItemDecoration() with single parameter doesn't make a difference in the output.Cadre
Could you show me your ItemDecoration class code please?Conyers
It's an anonymous inner class: new RecyclerView.ItemDecoration() { int space = 10; @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { outRect.left = space; outRect.right = space; outRect.bottom = space; if (parent.getChildAdapterPosition(view) == 0) outRect.top = space; } } But why should this code matter when app crashes even with LinearLayoutManager?Cadre
Ok, I was confused about the index of 2 before but I realise it's to be drawn 2nd, so the error is that you're telling it to draw the decoration 2nd, but you haven't told it to draw anything first. You should use the single parameter version since you only have 1 decoration to draw. Then, the reason the decoration might not be drawing may be because your item layout is too complex. Check out this link: #32543139Conyers
1. I have tried using the second parameter with various arguments. Any number other than 0 or less are crashing the app. 2. Single parameter version function makes no difference in the layout. 3. My item layout is a simple LinearLayout with just 2 views in it.Cadre
That makes sense. I'll make sure to update you the status as soon as I get the time to execute this code. Thanks!Cadre
Yes, the color of the dividers and the background color of the recycler view was the same and hence I was not able to notice the dividers. And thank you, your code did work but it is of no use to my app as I do not want to change the background color of the items in my recycler view. But for the main question, the function with two parameters is still giving the same error.Cadre
P
0

use this way:

create a shape with name divider_shape.xml

<?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/primary" />
</shape>

use DividerItemDecoration for vertical and horizental

val verticalDecorator = DividerItemDecoration(view.context, DividerItemDecoration.VERTICAL)
val horizontalDecorator = DividerItemDecoration(view.context, DividerItemDecoration.HORIZONTAL)

val drawable = ContextCompat.getDrawable(view.context, R.drawable.divider_shape)
verticalDecorator.setDrawable(drawable!!)
horizontalDecorator.setDrawable(drawable!!)

view.recyclerView.apply {
    addItemDecoration(verticalDecorator)
    addItemDecoration(horizontalDecorator)
    layoutManager = GridLayoutManager(view.context, 2)
    adapter = movieAdapter
}
Pentavalent answered 22/5, 2021 at 22:5 Comment(1)
Well not really, no, this also places a divider at the end of the last columns / rows.Ossieossietzky

© 2022 - 2024 — McMap. All rights reserved.