Skip to content

Instantly share code, notes, and snippets.

@pdegand
Created April 19, 2016 09:18
Show Gist options
  • Save pdegand/12418620d68a3313213fc08a8b3563bd to your computer and use it in GitHub Desktop.
Save pdegand/12418620d68a3313213fc08a8b3563bd to your computer and use it in GitHub Desktop.
A RecyclerView.ItemDecoration that you can apply on grids to have spacing between cells without using ugly margins on the cell layout. Feel free to use either the Kotlin version or the Java version.
/* The MIT License (MIT)
Copyright (c) 2016 Pierre Degand
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
import android.graphics.Rect;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
/**
* Apply a spacing around items of a grid. It works with GridLayoutManager and StaggeredGridLayoutManager
*/
public class GridSpacingItemDecorator extends RecyclerView.ItemDecoration {
private final int spacing;
/**
* @param spacing the spacing between each cell. In px.
*/
public GridSpacingItemDecorator(final int spacing) {
this.spacing = spacing;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (outRect != null && view != null && parent != null) {
final GridItemData gridItemData = extractGridData(parent, view);
int spanCount = gridItemData.getSpanCount();
int spanIndex = gridItemData.getSpanIndex();
int spanSize = gridItemData.getSpanSize();
outRect.left = (int) (spacing * ((spanCount - spanIndex) / (float) spanCount));
outRect.right = (int) (spacing * ((spanIndex + spanSize) / (float) spanCount));
outRect.bottom = spacing;
}
}
private GridItemData extractGridData(RecyclerView parent, View view) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
return extractGridLayoutData((GridLayoutManager) layoutManager, view);
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
return extractStaggeredGridLayoutData((StaggeredGridLayoutManager) layoutManager, view);
} else {
throw new UnsupportedOperationException("Bad layout params");
}
}
private GridItemData extractGridLayoutData(GridLayoutManager layoutManager, View view) {
GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) view.getLayoutParams();
return new GridItemData(
layoutManager.getSpanCount(),
lp.getSpanIndex(),
lp.getSpanSize()
);
}
private GridItemData extractStaggeredGridLayoutData(StaggeredGridLayoutManager layoutManager, View view) {
StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
return new GridItemData(
layoutManager.getSpanCount(),
lp.getSpanIndex(),
lp.isFullSpan() ? layoutManager.getSpanCount() : 1
);
}
private static class GridItemData {
private final int spanCount;
private final int spanIndex;
private final int spanSize;
private GridItemData(int spanCount, int spanIndex, int spanSize) {
this.spanCount = spanCount;
this.spanIndex = spanIndex;
this.spanSize = spanSize;
}
public int getSpanCount() {
return spanCount;
}
public int getSpanIndex() {
return spanIndex;
}
public int getSpanSize() {
return spanSize;
}
}
}
/* The MIT License (MIT)
Copyright (c) 2016 Pierre Degand
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
import android.graphics.Rect
import android.support.v7.widget.GridLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.StaggeredGridLayoutManager
import android.view.View
/**
* Apply a spacing around items of a grid. It works with GridLayoutManager and StaggeredGridLayoutManager
*/
class GridSpacingItemDecoration(val spacing: Int) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect?, view: View?, parent: RecyclerView?, state: RecyclerView.State?) {
if (outRect != null && view != null && parent != null) {
val (spanCount, spanIndex, spanSize) = extractGridData(parent, view)
outRect.left = (spacing * ((spanCount - spanIndex) / spanCount.toFloat())).toInt()
outRect.right = (spacing * ((spanIndex + spanSize) / spanCount.toFloat())).toInt()
outRect.bottom = spacing
}
}
private fun extractGridData(parent: RecyclerView, view: View): GridItemData {
val layoutManager = parent.layoutManager
if (layoutManager is GridLayoutManager) {
return extractGridLayoutData(layoutManager, view)
} else if (layoutManager is StaggeredGridLayoutManager) {
return extractStaggeredGridLayoutData(layoutManager, view)
} else {
throw UnsupportedOperationException("Bad layout params")
}
}
private fun extractGridLayoutData(layoutManager: GridLayoutManager, view: View): GridItemData {
val lp: GridLayoutManager.LayoutParams = view.layoutParams as GridLayoutManager.LayoutParams
return GridItemData(
layoutManager.spanCount,
lp.spanIndex,
lp.spanSize
)
}
private fun extractStaggeredGridLayoutData(layoutManager: StaggeredGridLayoutManager, view: View): GridItemData {
val lp: StaggeredGridLayoutManager.LayoutParams = view.layoutParams as StaggeredGridLayoutManager.LayoutParams
return GridItemData(
layoutManager.spanCount,
lp.spanIndex,
if (lp.isFullSpan) layoutManager.spanCount else 1
)
}
internal data class GridItemData(val spanCount: Int, val spanIndex: Int, val spanSize: Int)
}
@hariyogi
Copy link

but it is not giving spacing to first row.

Just add this in getItemOffSets :

int pos = parent.getChildAdapterPosition(view);
if (pos >= 0 && pos < your_collum){
outRect.top = spacing;
}
this works if your grid or stagger vertical

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment