Skip to content

Instantly share code, notes, and snippets.

@grandstaish
Last active January 7, 2022 11:31
Show Gist options
  • Save grandstaish/9eec95d879eb754cb5109caa49822dce to your computer and use it in GitHub Desktop.
Save grandstaish/9eec95d879eb754cb5109caa49822dce to your computer and use it in GitHub Desktop.
*Very* rough POC for what one of our common components at Monzo could look like in Compose
@Composable
@OptIn(ExperimentalSubcomposeLayoutApi::class)
fun ListSection(
modifier: Modifier = Modifier,
header: String? = null,
footer: String? = null,
showDividers: Boolean = true,
dividerInset: Dp = 16.dp,
content: @Composable () -> Unit,
) {
Column(modifier = modifier) {
if (header != null) {
Text(
modifier = Modifier.padding(top = 8.dp),
text = header,
style = MaterialTheme.typography.caption,
)
}
Surface(
color = MaterialTheme.colors.secondary,
shape = MaterialTheme.shapes.medium
) {
SubcomposeLayout<ListSectionSlots>(Modifier.fillMaxWidth()) { constraints ->
val sectionWidth = constraints.maxWidth
val itemMeasureables = subcompose(ListSectionSlots.Items, content)
val itemPlaceables = itemMeasureables.fastMap { it.measure(constraints) }
val sectionHeight = itemPlaceables.fastSumBy { it.height }
val dividerCount = if (showDividers) itemPlaceables.size - 1 else 0
val dividerMeasureables = subcompose(ListSectionSlots.Dividers) {
for (i in 0 until dividerCount) {
Divider(startIndent = dividerInset)
}
}
val dividerPlaceables = dividerMeasureables.fastMap { it.measure(constraints) }
layout(sectionWidth, sectionHeight) {
var y = 0
itemPlaceables.fastForEachIndexed { index, placeable ->
placeable.placeRelative(0, y)
y += placeable.height
if (index < dividerCount) {
val dividerPlaceable = dividerPlaceables[index]
dividerPlaceable.placeRelative(0, y - dividerPlaceable.height / 2)
}
}
}
}
}
if (footer != null) {
Text(
text = footer,
style = MaterialTheme.typography.caption,
)
}
}
}
private enum class ListSectionSlots {
Items,
Dividers
}
@grandstaish
Copy link
Author

grandstaish commented Sep 25, 2020

Usage:

@Composable
fun TestScreen() {
    ScrollableColumn(modifier = Modifier.padding(16.dp)) {
        ListSection {
            Text(text = "Item 1", modifier = Modifier.padding(16.dp))
            Text(text = "Item 2", modifier = Modifier.padding(16.dp))
            Text(text = "Item 3", modifier = Modifier.padding(16.dp))
            Text(text = "Item 4", modifier = Modifier.padding(16.dp))
        }
        ListSection(modifier = Modifier.padding(top = 16.dp)) {
            Text(text = "Item 5", modifier = Modifier.padding(16.dp))
            Text(text = "Item 6", modifier = Modifier.padding(16.dp))
            Text(text = "Item 7", modifier = Modifier.padding(16.dp))
            Text(text = "Item 8", modifier = Modifier.padding(16.dp))
        }
    }
}

Screenshot:

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