Zan Skamljic
05/28/2021, 6:47 AMekursakov
05/28/2021, 10:53 AMpostFling
method is called when scroll is ended, so you can animate there to some anchor.Zan Skamljic
05/28/2021, 12:31 PM@Composable
fun IndentedColumn(
items: List<String> = listOf(
"One",
"Two",
"Three",
"Four",
"Five",
"Six"
),
) {
val scrollState = rememberScrollState()
val scope = rememberCoroutineScope()
var size by remember { mutableStateOf(IntSize.Zero) }
val indices = remember { IntArray(items.size) { 0 } }
val flingBehavior = object : FlingBehavior {
override suspend fun ScrollScope.performFling(initialVelocity: Float): Float {
val value = scrollState.value
indices.minByOrNull { abs(it - value) }?.let {
scope.launch {
scrollState.animateScrollTo(it)
}
}
return initialVelocity
}
}
Box(modifier = Modifier.onSizeChanged { size = it }) {
Layout(
modifier = Modifier
.verticalScroll(
scrollState,
flingBehavior = flingBehavior
)
.background(Color.Gray),
content = {
items.forEach {
Text(text = it, color = Color.White)
}
}
) { measurables, constraints ->
val itemSpacing = 16.dp.roundToPx()
var contentHeight = (items.count() - 1) * itemSpacing
val placeables = measurables.mapIndexed { index, measurable ->
val placeable = measurable.measure(constraints.copy())
contentHeight += if (index == 0 || index == measurables.lastIndex) placeable.height / 2 else placeable.height
placeable
}
layout(constraints.maxWidth, size.height + contentHeight) {
val startOffset = size.height / 2 - placeables[0].height / 2
var yPosition = startOffset
val scrollPercent = scrollState.value.toFloat() / scrollState.maxValue
placeables.forEachIndexed { index, placeable ->
val ratio = index.toFloat() / placeables.lastIndex
val indent = cos((scrollPercent - ratio) * PI / 2) * size.width / 2
placeable.placeRelative(x = indent.toInt(), y = yPosition)
indices[index] = yPosition - startOffset
yPosition += placeable.height + itemSpacing
}
}
}
}
}
@Preview
@Composable
fun IndentedColumnPreview() {
ComposePatternTheme {
Box(
Modifier
.fillMaxWidth()
.height(300.dp),
contentAlignment = Alignment.Center
) {
IndentedColumn()
Divider(color = Color.Red)
Divider(
Modifier
.fillMaxHeight()
.width(1.dp), color = Color.Red
)
}
}
}
Ash
05/28/2021, 2:31 PMZan Skamljic
05/28/2021, 3:31 PM