Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save vyguera/e6babe1995bff6e8694c2a14b69c595c to your computer and use it in GitHub Desktop.
Save vyguera/e6babe1995bff6e8694c2a14b69c595c to your computer and use it in GitHub Desktop.
GridLayoutManager implementation that stretches to fit all grid items on screen and disables scrolling. Useful for dashboards etc.
package com.example;
import android.content.Context
import android.util.AttributeSet
import android.view.ViewGroup
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlin.math.ceil
import kotlin.math.roundToInt
class SpanningGridLayoutManager : GridLayoutManager {
private val horizontalSpace: Int
get() = width - paddingRight - paddingLeft
private val verticalSpace: Int
get() = height - paddingBottom - paddingTop
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) :
super(context, attrs, defStyleAttr, defStyleRes)
constructor(context: Context, spanCount: Int) : super(context, spanCount)
constructor(context: Context, spanCount: Int, orientation: Int, reverseLayout: Boolean) :
super(context, spanCount, orientation, reverseLayout)
override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams {
return spanLayoutSize(super.generateDefaultLayoutParams())
}
override fun generateLayoutParams(c: Context, attrs: AttributeSet): RecyclerView.LayoutParams {
return spanLayoutSize(super.generateLayoutParams(c, attrs))
}
override fun generateLayoutParams(lp: ViewGroup.LayoutParams): RecyclerView.LayoutParams {
return spanLayoutSize(super.generateLayoutParams(lp))
}
override fun checkLayoutParams(lp: RecyclerView.LayoutParams): Boolean {
val layoutParams = generateDefaultLayoutParams()
return super.checkLayoutParams(lp) &&
layoutParams.width == lp.width &&
layoutParams.height == lp.height
}
private fun spanLayoutSize(layoutParams: RecyclerView.LayoutParams): RecyclerView.LayoutParams {
when (orientation) {
HORIZONTAL -> layoutParams.width = (horizontalSpace / maxItemsInAllLines()).roundToInt()
VERTICAL -> layoutParams.height = (verticalSpace / maxItemsInAllLines()).roundToInt()
}
return layoutParams
}
override fun canScrollVertically(): Boolean = false
override fun canScrollHorizontally(): Boolean = false
private fun maxItemsInAllLines(): Double = ceil(itemCount / spanCount.toDouble())
}
@anta40
Copy link

anta40 commented Oct 19, 2022

Hi @vyguera, I'm using your code on a small screen (240x320) to display a 3x3 grid. Width wise, yes it's nicely divided into 3 columns.
There's a small issue. Some part of the bottom row is not visible. Quick hack is override fun canScrollVertically(): Boolean = true.

I wonder, though. Is there a way to make this 3x3 grid automatically stretch both width and height-wise without scrolling?

@dstd
Copy link

dstd commented Jun 9, 2023

Have you ever caught a crash ArrayIndexOutOfBoundsException: length=0; index=-1 when the size of items change? Like while RecyclerView dimensions or span count change.

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