Created
May 30, 2021 08:31
-
-
Save zskamljic/74a2aae3257197a8a8374f61ecfdc956 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Composable | |
fun CurvedScroll( | |
itemCount: Int, | |
item: @Composable (Int) -> Unit | |
) { | |
val scrollState = rememberScrollState() | |
// Added: to hold the size of the composable | |
var size by remember { mutableStateOf(IntSize.Zero) } | |
Box(modifier = Modifier.onSizeChanged { size = it }) { | |
Layout( | |
modifier = Modifier.verticalScroll(scrollState), | |
content = { repeat(itemCount) { item(it) } } | |
) { measurables, constraints -> | |
val itemSpacing = 16.dp.roundToPx() | |
// Added: to hold the height of children, we can already calculate the amount of space between them | |
var contentHeight = (itemCount - 1) * itemSpacing | |
// Updated: use index for special handling of first and last items | |
val placeables = measurables.mapIndexed { index, measurable -> | |
val placeable = measurable.measure(constraints) | |
// First and last items should be centered, meaning half of the view is above center line and half below | |
contentHeight += if (index == 0 || index == measurables.lastIndex) { | |
placeable.height / 2 | |
} else { | |
placeable.height | |
} | |
placeable | |
} | |
// Updated: use the height of Box to allow for vertical centering, half the height comes before first item, half after the last | |
layout(constraints.maxWidth, size.height + contentHeight) { | |
// Calculate the value so that first item is centered vertically | |
val startOffset = size.height / 2 - placeables[0].height / 2 | |
// All items should be placed according to it | |
var yPosition = startOffset | |
placeables.forEach { placeable -> | |
placeable.placeRelative(x = 0, y = yPosition) | |
yPosition += placeable.height + itemSpacing | |
} | |
} | |
} | |
} | |
} | |
@Preview | |
@Composable | |
fun CurvedScrollPreview() { | |
val items = listOf( | |
"One", | |
"Two", | |
"Three", | |
"Four", | |
"Five", | |
"Six" | |
) | |
CustomTheme { | |
Box( | |
modifier = Modifier | |
.background(Color.Gray) | |
.height(300.dp), | |
contentAlignment = Alignment.Center, | |
) { | |
CurvedScroll(items.count()) { | |
Text(text = items[it], style = MaterialTheme.typography.h4) | |
} | |
// Added as a helper, to see the vertical center and make sure views are at their proper positions | |
Divider(color = Color.Red) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment