Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine column position in staggered grid layout manager

Tags:

I’m using a staggered recycler view layout for a list of photos. I want the spacing on the sides to be zero while still having space between the two columns. I’m using an item decoration sub class to get the spacing seen in the attached photo. I know I have control over the left and right spacing but the problem is that I never know which column the photo is in. It seems like the staggered layout manager does some of its own reordering. I've tried using getChildAdapterPosition but it seems to return the position in the data source array and not the actual position of the photo in the layout. Any idea how I should approach this? enter image description here

like image 793
Richmond Watkins Avatar asked Feb 03 '16 21:02

Richmond Watkins


People also ask

How do I set GridLayoutManager spacing?

In your source code, add ItemOffsetDecoration to your RecyclerView. Item offset value should be half size of the actual value you want to add as space between items. mRecyclerView. setLayoutManager(new GridLayoutManager(context, NUM_COLUMNS); ItemOffsetDecoration itemDecoration = new ItemOffsetDecoration(context, R.

What is the difference between a staggered grid and a normal grid?

In this each Grid is of same size (Height and width). Grid View shows symmetric items in view. Staggered Grid View : It is basically an extension to Grid View but in this each Grid is of varying size(Height and width). Staggered Grid View shows asymmetric items in view.

What is staggered LayoutManager?

As per doc, Staggered layout manager is a LayoutManager that lays out children in a staggered grid formation. It supports horizontal & vertical layout as well as an ability to layout children in reverse.

What is use of GridLayoutManager?

RecyclerView Using GridLayoutManager With Example In Android Studio. In Android, RecyclerView is an advance and flexible version of ListView and GridView. It is a container used to display large amount of data sets that can be scrolled very efficiently by maintaining a limited number of views.

What is staggered grid LayoutManager?

A LayoutManager that lays out children in a staggered grid formation. It supports horizontal & vertical layout as well as an ability to layout children in reverse. Staggered grids are likely to have gaps at the edges of the layout.

How do I avoid gaps in staggeredgridlayoutmanager?

Staggered grids are likely to have gaps at the edges of the layout. To avoid these gaps, StaggeredGridLayoutManager can offset spans independently or move items between spans. You can control this behavior via setGapStrategy (int).

How to enable column spacing in Android recyclerview gridlayoutmanager?

This example demonstrates about Android Recyclerview GridLayoutManager column spacing Step 1 − Create a new project in Android Studio, go to File ⇒ New Project and fill all required details to create a new project. Step 2 − Add the following code to res/layout/activity_main.xml. In the above code, we have taken recyclerview.

What is the use of gridlayoutmanager in Android?

GridLayoutManager: It is used to show item views grid views. StaggeredLayoutManager: It is used to show item views in staggered views. We can also create a custom layout manager by RecyclerView.LayoutManager class.


2 Answers

I managed to get it working. In my case, I don't need any borders on the left or right edges of the screen. I just need borders in the middle and bottom. The solution is to get the layout parameters of the view that are of type StaggeredGridLayoutManager.LayoutParams. In those parameters you can get the spanIndex that tells you on which index the view is. So if you have a spanCount of 2, the left view will have a spanIndex of 0 and the right view will have a spanIndex of 1.

Here is my code, maybe it help you.

public class SpaceItemDecoration extends RecyclerView.ItemDecoration {     private int space;      public SpaceItemDecoration(int space) {         this.space = space;     }       @Override     public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {         int position = parent.getChildAdapterPosition(view);          StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();         int spanIndex = lp.getSpanIndex();          if (position > 0) {             if (spanIndex == 1) {                 outRect.left = space;             } else {                 outRect.right = space;             }              outRect.bottom = space * 2;         }     } } 

In my case, firstly I have to get the position, since on the index 0 I have a header View, which doesn't have any borders. After that, I get the span index and depending on it I set the borders that I need on that View. And finally I set the bottom border on every View.

like image 88
Tooroop Avatar answered Sep 28 '22 12:09

Tooroop


so the one solution I was able to use was with an item decorator but it definitely is a little weird/hacky feeling.

Basically you'll adjust the outer rectangle of the item based on its column position (or something similar). My understanding is that the outer rectangle is more or less the spacing you want to change. Give the code below a try, obviously you'll need to make your own adjustments and logic to 'calculate' which column the item is on but this should be enough to figure it out, hopefully:

recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {         public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {             int left = outRect.left;             int right = outRect.right;             int top = outRect.top;             int bottom = outRect.bottom;             int idx = parent.getChildPosition(view);             int perRow = gridLayoutManager.getSpanCount();              int adj = blahh... // some adjustment              if (idx < itemsPerRow) {                 // on first row, adjust top if needed             }             if(idx % perRow == 0){                 // on first column, adjust. Left magically adjusts bottom, so adjust it too...                 left += adj;                 bottom -= adj;            }             if(idx % itemsPerRow == perRow - 1){                // on last column, adjust. Right magically adjusts bottom, so adjust it too...                right += adjustment;                bottom -= adjustment;            }              outRect.set(left, top, right, bottom);         }     }); 

Again this is hacky and takes some trial and error to get right.

Another solution I have tried with some success is to define different views for the different columns. In your case the columns would have views with different, negative margins, on the left and right to get the effect you want.

As a side note, I assume you are using an elevation on the card view. One thing I've noticed is that if the card view does NOT have elevation and instead you handle it yourself (yeah, i know, isn't the point to not handle elevation yourself) much of this difficulty goes away and things start to behave, likely because of the elevation/shadow calculations. But anyway... Hope this is at least somewhat helpful...

like image 30
Robert Dale Johnson III Avatar answered Sep 28 '22 10:09

Robert Dale Johnson III