android 创建一个可拖动的元素,当用户抬起手指时,该元素将返回到其原始位置

ippsafx7  于 2023-02-20  发布在  Android
关注(0)|答案(1)|浏览(204)

我正在使用Android Jetpack Compose实现一个可拖动的元素,当用户抬起手指时,它会平滑地返回到原来的位置。我来了一些实现,我真的不喜欢它。

@Composable
fun dragAndBack2() {
    var offset by remember { mutableStateOf(IntOffset.Zero) }
    var isAnimating by remember { mutableStateOf(false) }

    var animate = animateIntOffsetAsState(
        targetValue = if (isAnimating) {
            IntOffset.Zero
        } else offset,
        animationSpec = tween(
            durationMillis = 1000,
            easing = LinearEasing
        ),
        finishedListener = {
            offset = IntOffset.Zero
        }

    )
    Box(
        modifier = Modifier
            .offset { if (isAnimating) animate.value else offset }
            .pointerInput(Unit) {
                detectDragGestures(
                    onDragCancel = { isAnimating = true },
                    onDragStart = { isAnimating = false },
                    onDragEnd = { isAnimating = true },
                    onDrag = { change, dragAmount ->
                        change.consumeAllChanges()
                        val offsetChange =
                            IntOffset(dragAmount.x.roundToInt(), dragAmount.y.roundToInt())
                        offset = offset.plus(offsetChange)
                    }
                )
            }
            .background(Color.Blue)
            .size(50.dp)
    )
}

它可以工作,但当手指被提起时,元素会跳到离手指一段距离的地方,就像跳到上次保存的位置一样。

@Composable
fun AnimatedBox() {
    var isAnimating by remember { mutableStateOf(false) }
    val transition = updateTransition(targetState = !isAnimating)

    var offset by remember { mutableStateOf(IntOffset.Zero) }

    val transitionOffset by transition.animateIntOffset(
        transitionSpec = {
            keyframes {
                durationMillis = 1000
                offset at 0 with LinearOutSlowInEasing // start value
                IntOffset.Zero at 500
            }
        },
        label = "boxSize"
    ) { b ->
        if (b) {
            offset
        } else {
            IntOffset.Zero
        }
    }

    Box(
        modifier = Modifier
            .offset { transitionOffset }
            .pointerInput(Unit) {
                detectDragGestures(
                    onDragStart = {
                        offset = IntOffset.Zero
                        isAnimating = false
                    },
                    onDragEnd = {
                        isAnimating = true
                    },
                    onDrag = { change, dragAmount ->
                        change.consumeAllChanges()
                        val offsetChange =
                            IntOffset(dragAmount.x.roundToInt(), dragAmount.y.roundToInt())
                        offset = offset.plus(offsetChange)
                    }
                )
            }
            .background(Color.Blue)
            .size(50.dp)
    )
}

同样可以实现,但如果手指不动,元素会快速移回原位,两个版本的实现也都有一定的延迟,提前感谢。

xlpyo6sf

xlpyo6sf1#

最后我解决了这个问题。这里是手指和元素之间的一些延迟。但是它像我想要的那样工作。

@Composable
    fun onTouchWithTransition(position: IntOffset, sizeDp: Dp) {

        val fingerPosition by remember { mutableStateOf(Position(position)) }
        val placeToReturn by remember { mutableStateOf(Position(position)) }

        var testTransition: Position by remember {
            mutableStateOf(fingerPosition)
        }

        var transition: Transition<Position> = updateTransition(targetState = testTransition)

        val transitionOffset by transition.animateIntOffset(
            transitionSpec = {
                keyframes {
                    durationMillis = 500
                }
            },
            label = "label"
        ) {
            it.offset
        }


        Box(modifier = Modifier
            .offset { transitionOffset }
            .clip(CircleShape)
            .background(Color.Red)
            .pointerInput(Unit) {
                detectDragGestures(
                    onDragStart = {
                        fingerPosition.offset = position
                        testTransition = fingerPosition
                    },
                    onDragEnd = { testTransition = placeToReturn },
                    onDrag = { change, dragAmount ->
                        change.consumeAllChanges()
                        val offsetChange =
                            IntOffset(dragAmount.x.roundToInt(), dragAmount.y.roundToInt())
                        fingerPosition.offset = fingerPosition.offset.plus(offsetChange)
                    }
                )
            }
            .size(sizeDp, sizeDp)
        )
    }

    class Position(private var off: IntOffset) {
        var offset: IntOffset by mutableStateOf(off)
    }

相关问题