I'm new to both Kotlin and Jetpack Compose, and am trying to implement a custom composable which takes in a list of cells and a number of columns, and lays it out in a table format. Each cell in the table can hold any content. Essentially a grid of fixed column count which has borders for all its cells.
Ultimately I would like to use my table like so:
Table(2) {
SomeContent(onclick = { /**/ })
SomeOtherContent()
Text("Some text")
//etc...
}
Beyond laying out the content in a table format, there are two additional things I want to accomplish:
- I don't want to have to manage border logic in the cells themselves. The table should add borders to each cell as appropriate. I would ideally be able to accomplish this by wrapping each child in a box with the needed borders.
- If I pass in some number of cells such that the last row of the table is not completely filled, I would like my table function to add additional empty cells (so that borders still show for cells without content). To do this I need to know the number of children contained in the content, as well as be able to add new children.
A Note: I don't think this matters for my issue, but I'm using Compose Multiplatform to develop for desktop platforms, not mobile. From what I understand, most things carry over directly, however Android specific APIs are not available to me.
So far, I have come up with this code, which gets me close to what I want:
@Composable
fun Table(
columnCount: Int,
cellContent: @Composable () -> Unit //might not contain correct number of cells to fill the table
) {
Layout(
content = cellContent
) { measurables, constraints ->
//layout logic to produce a table
}
}
But unfortunately, while this does produce a table, it fails at my other goals, because I can't figure out how to access the children passed into my composable as a list of elements that can be modified. It seems possible to get a list of something, because the MeasureScope
inside the Layout
lambda provides a list of measurables, but I'm unsure what I would need to do to modify said list either. I feel like I'm missing something very simple and it's driving me up the wall.
Per this answer: https://stackoverflow.com/a/69649279 I tried passing in a list of non composable objects and a content builder function like so:
@Composable
fun<T> Table(
columnCount: Int,
cellData: List<T>,
cellContent: @Composable (item: T) -> Unit
)
But the issue with that is that cell content can be anything at all, and it seems silly that the Table would need to care about how any particular cell is constructed when all it should be doing is measuring its children and arranging them. What if I want some of my cells to have a onClick callback but not others? What if I have dozens of different types of cells all requiring different arguments?
My question:
How can I access and modify the content passed into my table as a list, so that I can modify each child before the layout actually occurs (or during the MeasureScope
provided by the Layout
function), as well as add additional child content as needed? If this is impossible, what approach should I take instead?