Reputation: 173
This is what I have to create in Jetpack Compose:
This seems like a job for a LazyHorizontalGrid but it tries to fill the height of the screen by default. I can give it a fixed height but letting it wrap content height seems to be impossible.
I tried letting it wrap content height by using the .wrapContentSize() modifier which did nothing and I tried setting it's height to the minimum intrinsic size but this is not supported.
Column(modifier = modifier.verticalScroll(scrollState)) {
LazyHorizontalGrid(
rows = GridCells.Fixed(2),
modifier = modifier.heightIn(max = 200.dp),
contentPadding = PaddingValues(horizontal = 24.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
items(items = contentTypes) { contentType ->
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.background(color = LocalCustomColors.current.surface, shape = RoundedCornerShape(12.dp))
.padding(all = 8.dp)
.width(80.dp)
) {
GenericIcon(
drawableId = contentType.icon
)
Spacer(modifier = Modifier.height(4.dp))
Caption3Text(
text = stringResource(contentType.text),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
}
}
}
Upvotes: 2
Views: 166
Reputation: 173
Not an answer but this is the workaround I created for now:
@Composable
fun <T> GenericHorizontalGrid(
items: List<T>,
rowCount: Int,
visibleItemCount: Int,
horizontalItemSpacing: Int,
verticalItemSpacing: Int,
horizontalContentPadding: Int,
extraEndSpacing: Int,
modifier: Modifier = Modifier,
itemContent: @Composable (T, Modifier) -> Unit,
) {
val scrollState = rememberScrollState()
val screenWidth = LocalConfiguration.current.screenWidthDp
val totalNegativeSpace = ((visibleItemCount - 1) * horizontalItemSpacing) + horizontalContentPadding + extraEndSpacing
val itemWidth = (screenWidth - totalNegativeSpace) / visibleItemCount
val chunkSize = ceil(items.size / rowCount.toFloat()).toInt()
val rows: List<List<T>> = items.chunked(chunkSize)
Column(
modifier = modifier
.horizontalScroll(scrollState)
.padding(horizontal = horizontalContentPadding.dp)
) {
rows.forEachIndexed { rowIndex, row ->
Row {
row.forEachIndexed { themeIndex, item ->
itemContent(
item,
Modifier.width(itemWidth.dp)
)
if (themeIndex < row.lastIndex) {
Spacer(modifier = Modifier.width(horizontalItemSpacing.dp))
}
}
}
if (rowIndex < rows.lastIndex) {
Spacer(modifier = Modifier.height(verticalItemSpacing.dp))
}
}
}
}
This generic approach may not be lazy rendering items but in my case the item list wasn't very long. Here is how you can use this generic composable to achieve the desired result shown in the question:
@Composable
private fun DiscoverContentTypes(
contentTypes: List<DiscoverContentType>,
modifier: Modifier = Modifier
) {
val screenWidth = LocalConfiguration.current.screenWidthDp
GenericHorizontalGrid(
items = contentTypes,
rowCount = 2,
visibleItemCount = when {
screenWidth < 360 -> 2
screenWidth < 800 -> 3
else -> 5
},
horizontalItemSpacing = 12,
verticalItemSpacing = 8,
horizontalContentPadding = 24,
extraEndSpacing = 48,
modifier = modifier
.padding(top = 4.dp)
) { contentType, itemModifier ->
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = itemModifier
.background(color = LocalCustomColors.current.surface, shape = RoundedCornerShape(12.dp))
.padding(all = 8.dp)
) {
GenericIcon(
drawableId = contentType.icon,
tint = LocalCustomColors.current.darkModeAwareTextColor
)
Spacer(modifier = Modifier.height(4.dp))
Caption3Text(
text = stringResource(contentType.text)
)
}
}
}
Should anyone find and post a proper solution I'll make sure to mark it as the correct answer.
Upvotes: 0