Jetpack Compose中可拖动项的偏移动画如何重置?

6

我有一个绿色正方形,可以在垂直方向上拖动。但是每当我停止拖动时,我希望它能够通过动画将偏移重置到起始位置。我尝试了下面的方法,但是我无法解决它。有人知道如何做吗?

@Composable
fun DraggableSquare() {
    var currentOffset by remember { mutableStateOf(0F) }
    val resetAnimation by animateIntOffsetAsState(targetValue = IntOffset(0, currentOffset.roundToInt()))

    var shouldReset = false

    Box(contentAlignment = Alignment.TopCenter, modifier = Modifier.fillMaxSize()) {
        Surface(
            color = Color(0xFF34AB52),
            modifier = Modifier
                .size(100.dp)
                .offset {
                    when {
                        shouldReset -> resetAnimation
                        else -> IntOffset(0, currentOffset.roundToInt())
                    }
                }
                .draggable(
                    state = rememberDraggableState { delta -> currentOffset += delta },
                    orientation = Orientation.Vertical,
                    onDragStopped = {
                        shouldReset = true
                        currentOffset = 0F
                    }
                )
        ) {}
    }
}
1个回答

15
您可以将偏移量定义为Animatable。 在拖动时,使用snapTo方法将当前值更新为初始值,并使用onDragStopped开始动画。
val coroutineScope = rememberCoroutineScope()
val offsetY  =  remember { Animatable(0f) }

Box(contentAlignment = Alignment.TopCenter, modifier = Modifier.fillMaxSize()) {
    Surface(
        color = Color(0xFF34AB52),
        modifier = Modifier
            .size(100.dp)
            .offset {
                IntOffset(0, offsetY.value.roundToInt())
            }
            .draggable(
                state = rememberDraggableState { delta ->
                    coroutineScope.launch {
                        offsetY.snapTo(offsetY.value + delta)
                    }
                },
                orientation = Orientation.Vertical,
                onDragStopped = {
                    coroutineScope.launch {
                        offsetY.animateTo(
                            targetValue = 0f,
                            animationSpec = tween(
                                durationMillis = 3000,
                                delayMillis = 0
                            )
                        )
                    }
                }
            )
    ) {
    }
}

enter image description here


不错,这解决了重置部分的问题,但我还希望重置能够配有平滑动画。这可能吗? - Donny Rozendal
@DonnyRozendal 我已更新答案以添加动画。 - Gabriele Mariotti
1
您真是个英雄,非常感谢!代码真的很干净易读。我的另一个解决方案涉及多个状态,导致了竞争条件,因此将所有内容放在一个Animatable中是正确的选择。我也有这个想法,但不想动画拖动。但我看到您使用了“snapTo”来解决这个问题,这真是太聪明了。 - Donny Rozendal
另外,在 snapTo 函数内部,应该写成 offsetY 而不是 offsetX。但由于字符数不足,我无法请求编辑。 - Donny Rozendal
请解释一下为什么在这里需要使用“协程作用域”? - lr058
@Ir058 snapToanimateTo都是挂起函数,需要使用作用域来调用它们。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接