In the Android View
system with a RecyclerView
, one could have the GridLayoutManager
decide at runtime the number of "Spans" each item used by using a callback called spanSizeLookup
:
Imagine you have
val layoutManager = GridLayoutManager(this, 2) //Two Spans Max
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
// calculate based on whatever you want and return N
return if (adapter.getItem(position).xx = YY) 1 else 2 //e.g.
}
}
Now I'm attempting to convert this to Compose using LazyVerticalGrid
where there's no Adapter, and certainly no LayoutManager to deal with. However, I'm having hard time finding the equivalent to the spanSizeLookup.
Initial Option: using the "DSL"
Imagine a @Composable
that receives the "data
" and does something like:
LazyVerticalGrid(columns = GridCells.Fixed(2)) {
items(data) { anItem ->
// some composable to show "anItem"
}
}
This is fine, it will display each item in a "two" column (spans!) layout; what if you want to dynamically change the span for each item?
No problem, the items
function in the DSL actually does take a span:
items(data, span = { // put your span here }) { anItem ->
// some composable to show "anItem"
}
This span
is going to apply to all items and you cannot change it... so this doesn't solve the problem.
The function block for span
is expecting a GridItemSpan(Int)
.
So the 1st question is: Would there be a way to change this from inside the content block? Think of something like this:
items(data) { anItem ->
// Lookup the correct span for this `item`
span = if (anItem.xx = YY) 1 else 2
// some composable to show "anItem"
}
This is obviously not possible like that...
The Alternative
What one CAN do, is create individual item
s which also accept a span and only apply to the actual item:
// Manually iterate all items
data.forEach { anItem ->
if (anItem.xx = YY) {
// Render the item with 1 span.
item(span = { GridItemSpan(1) }) {
// some composable to show...
}
} else {
// Render the item with 2 spans.
item(span = { GridItemSpan(1) }) {
// some composable to show...
}
}
}
This works (I've tested it) but it feels a bit convoluted.
Question 2 is then: Is this "ok" according to the current (1.3.0-alpha01) version of Compose? Is there a better way?
Please keep in mind I tried to abstract the irrelevant parts of all this, so it's a bit of pseudo-code here and there to illustrate a point.
I have seen this post and similar ones, but I'm not sure if that's the right approach either, seems like a lot of complexity for something the framework APIs could better handle. I'd love to hear more about it though.
I've naturally read the official documentation to no avail.