16

I am looking to create the following layout (red sqaures does not really have to be squares, a custom fixed height is also fine). The layout seems very simple yet I did not find a layout manager which suits my needs.

wat i want

I tried the StaggeredGridLayoutManager but this only allows to set the span of either the column or the row, not both.

Is there floating around a custom layout manager which is able to do this? I have looked at TwoWayView but changing height seems to be problematic and the library is not being maintained.

Anyone having this problem and solved it?

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Brianvdb
  • 666
  • 1
  • 6
  • 16
  • Check this: http://stackoverflow.com/questions/36514887/layoutmanager-for-recyclerview-grid-with-different-cell-width/36518658#36518658 – Farshad Jul 08 '16 at 20:54
  • @Brianvdb have you solve this if yes can you help me to get out from this.It will be great help thanks... – Sagar Feb 16 '18 at 09:16

2 Answers2

22

A little bit late, but it might help everyone else...

I was looking for the same and finally, after 2 days of googling I found a solution. Big thanks to Nick Butcher! His layout manager called SpannableGridLayoutManager is capable of doing this. In my case I was doing a pattern like your first two rows:

enter image description here

Solution is easy:

1. Download SpannableGridLayoutManager from here

For some reason I had to change this line:

while (availableSpace > 0 && lastVisiblePosition < lastItemPosition) {

to

while (lastVisiblePosition < lastItemPosition) {

to got the manager working.

2. Set SpannableGridLayoutManger to your RecyclerView

In my case:

    SpannedGridLayoutManager manager = new SpannedGridLayoutManager(
            new SpannedGridLayoutManager.GridSpanLookup() {
                @Override
                public SpannedGridLayoutManager.SpanInfo getSpanInfo(int position) {
                    // Conditions for 2x2 items 
                    if (position % 6 == 0 || position % 6 == 4) {
                        return new SpannedGridLayoutManager.SpanInfo(2, 2);
                    } else {
                        return new SpannedGridLayoutManager.SpanInfo(1, 1);
                    }
                }
            },
            3, // number of columns
            1f // how big is default item
    );

Which gave me exactly what I wanted (numbers are position of item in adapter):

enter image description here

EDIT: error with styleable Put those lines into attrs.xml

<declare-styleable name="SpannedGridLayoutManager">
    <attr name="android:orientation" />
    <attr name="spanCount" />
    <attr name="aspectRatio" format="string" />
</declare-styleable>
kristyna
  • 1,360
  • 2
  • 24
  • 41
  • I am trying your answer however, there is an error on line 54 `TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.SpannedGridLayoutManager, defStyleAttr, defStyleRes);` - `//R.styleable.SpannedGridLayoutManager` is not found – SNos Oct 26 '17 at 14:55
  • @SNos see the edit. You have to declare a style for your manager – kristyna Oct 27 '17 at 09:04
  • @kristyna when I add 7 images in recyclerview and after scroll then 6 number position image display only half and when I add 1 more image in a list then scroll it's working well. How it solve?can you help me? – Mahesh Vayak Feb 08 '18 at 04:35
  • @kristyna do you have example for this please help – Sagar Feb 16 '18 at 09:11
  • @MaheshVayak I would have to see the code. Do you have some margins or paddings in the layout which can cause seeing just a half? – kristyna Feb 16 '18 at 11:09
  • @kristyna thanks for help , I have solved and got the expected result – Sagar Feb 16 '18 at 11:14
  • @kristyna, there is a problem with this `LayoutManager` as when there is one item, its not showing, any help? – blueware May 13 '18 at 12:14
  • Mine code is working fine even for one item. Sorry I cant help. The only workaround can be setting different LayoutManger in case you have only one item. – kristyna May 13 '18 at 23:59
  • @kristyna, would you mind sharing your final `SpannedGridLayoutManager` code with us? – blueware May 14 '18 at 09:50
  • @kristyna would you mind helping me out? https://i.imgur.com/6HlqwFn.jpg here is the screenshot. I am not able to scroll, so that I can see the rest of the big image. If I remove the smaller one, then scroll works correctly. I use version published in github. For SpanInfo I just return 2x2 if position % 6 == 0. – cheshie Aug 02 '18 at 08:50
  • 2
    I have managed to fix the issue for our particular case. problem lied in scrollVerticallyBy(), else clause. LayoutManager would take the last item. If item previous to last had span bigger than the last one, i.e., 2x2 vs 1x1, then list would not scroll, because the "bottom" value was from the smaller item. I have hardcoded, that if previous item was the big one, then take the "bottom" value from that one. However this is not a general solution. Hope this will help someone. – cheshie Aug 02 '18 at 14:11
  • @kristyna How to get first and last visible item position? – Himanshu Jul 12 '19 at 12:02
  • thanks fow verry helpful answer, please tell me, // Conditions for 2x2 items if (position % 6 == 0 || position % 6 == 4) , whats must i do if i want to show for 3x3 items. thanks – Yudi karma Aug 02 '19 at 08:44
  • after follow your answer, i got some issue, please check my question on stackoverflow https://stackoverflow.com/questions/57351715/recyclerview-takes-lots-of-space-from-top-after-use-spannedgridlayoutmanager – Yudi karma Aug 05 '19 at 03:20
  • @Yudikarma I dont have the project to try it, but if you want 3x3 (and 3 small items items on the side) then it would be (position % 8 == 0 || position % 8 == 5) return new SpannedGridLayoutManager.SpanInfo(3, 3); And also if I am not wrong you have to change the column number to 4. – kristyna Aug 06 '19 at 21:18
  • You are a life saver ! How did find this !?? – user987760 Oct 03 '19 at 15:30
  • Please find the latest SpannedGridLayoutManager in `grid_span` branch, which fixed many issues I met by the version of the original post. [link](https://github.com/android/plaid/blob/grid_span/app/src/main/java/io/plaidapp/ui/recyclerview/SpannedGridLayoutManager.java) – Richard Chang Nov 29 '19 at 04:13
  • Hello All! Thanks for this! Awesome. I only have a small issue. I do not want to have nested scrolling inside my recycler view. I changed the canScrollVertically to false but then not all items are showing in the main Scrollview. Do you have any idea how to fix? – Mehdi Satei Jan 13 '20 at 09:37
  • @MehdiSatei you don't want the recycler view to scroll? Maybe it doesn't show because there is not enough space for all the items? I can only guess here. I have never tried that. – kristyna Jan 13 '20 at 19:32
  • @kristyna I don't want a nested scroll inside the recycler view. What I have in my activity is a ScrollView with multiple recycelerviews. What I would like to have is a simple scrolling behaviour as a flat page. But what I have is a scrolling recycerview inside a scrollview (nested scrolling). If I turn off the nested scrolling, it will disappear completley – Mehdi Satei Jan 14 '20 at 15:08
  • Can anyone tell me? Can I set different 'cellAspectRatio' for each cell of the item? – Nabin May 05 '20 at 10:19
  • I have some issues while integrating this library. How to remove extra space of item https://github.com/android/plaid/issues/830 – Nabin May 08 '20 at 05:48
  • There is little issue in the code. When there is only 1 item, it is not visible at all. Can someone suggest me solution. – Jay Vyas Oct 26 '21 at 05:45
6

Finally did it, it will help everyone who is trying to achieve any kind of patterns

I was looking for the same result but with one header and lazy loading footer. I tried @Kristyna answers of Nick Butcher Library too. But it has many issues like fast scrolling view disappear problem with the extra space or fixed cell height issue.

I found another library of Arasthel SpannedGridLayoutManager and tried to implement it. But it also has many issues like fixed height and footers extra space issue

Finally, after 5hr of digging Arasthel's SpannedGridLayoutManager, I fixed the issues and found my result.

My final edited forked library download from here SpannedGridLayoutManager.

enter image description here

In my case

  val adapter = GridItemAdapter()//This is your adapter
  val spannedGridLayoutManager = SpannedGridLayoutManager(orientation = VERTICAL, spans = 3)
  spannedGridLayoutManager.itemOrderIsStable = true
  recyclerview.layoutManager = spannedGridLayoutManager

And

  spannedGridLayoutManager.spanSizeLookup = SpannedGridLayoutManager.SpanSizeLookup { position ->
        when {
            position == 0 -> {
                /**
                 * 150f is now static 
                 * should calculate programmatically in runtime
                 * for to manage header hight for different resolution devices
                 */
                SpanSize(3, 1, 150f)
            }
            position % 7 == 1 ->
                SpanSize(2, 2)
            else ->
                SpanSize(1, 1)
        }
    }
  recyclerview.adapter = adapter

This spanSizeLookup logic may vary according to the requirement, for me I had set it randomly for testing purposes.

Nabin
  • 1,451
  • 3
  • 19
  • 26
  • @WebDiva you can use this class anywhere if your projects are in JAVA. – Nabin Jan 22 '21 at 14:47
  • It throws 'java.lang.ArithmeticException: divide by zero at com.arasthel.spannedgridlayoutmanager.SpannedGridLayoutManager.fillAfter(SpannedGridLayoutManager.kt:623) – WebDiva Jan 22 '21 at 14:48
  • @WebDiva Which branch are you using? Try custom-layoutparams branch – Nabin Jan 22 '21 at 14:51
  • @WebDiva sorry there is no custom-layoutparams, use dev or dynamic_layout. – Nabin Jan 22 '21 at 14:55
  • Sorry I was using the default implementation. I have changed it to yours now. Let's if it works now. – WebDiva Jan 22 '21 at 14:56
  • The issue persists. I think this is the issue. I have an adapter of empty arraylist. The arraylist is filled after after a network call. Maybe because the size of the items in the arraylist are 0 before the network call, it could crash. But this is not the case with LinearLayoutManger, GridLayoutManager or StaggeredGridLayoutManager. – WebDiva Jan 22 '21 at 15:03
  • @WebDiva which branch are you using? – Nabin Jan 22 '21 at 15:05
  • I am using your branch. – WebDiva Jan 22 '21 at 15:06
  • @WebDiva I have more than 3 branch, can you name it? – Nabin Jan 22 '21 at 15:07
  • Sorry. I don't know. I followed your link and got the spannedgridlayoutmanager code right away. – WebDiva Jan 22 '21 at 15:09
  • Okay so I was using your dev branch. This line of code ```val lastAddedRow = (layoutEnd - extraHeight) / rectsHelper.itemSize``` in the fillAfter() method is the culprit. – WebDiva Jan 26 '21 at 05:10
  • This is because you haven't provided height of recycler view in case of orientation horizontal and width in case of vertical – Yogesh Choudhary Paliyal Dec 24 '21 at 11:51
  • This seems to cut off parts of the last elements in certain cases, when the last items are all bigger than 1x1. Any idea why this could happen? I'm using the dev branch – abbath Nov 01 '22 at 14:17
  • Please try other branches as per required like: dynamic_layout, fix-empty-space-at-bottom or get_2×2_layout_position. – Nabin Nov 04 '22 at 06:02