Home > Back-end >  How can I animateTo diagonally in Compose and coroutineScope?
How can I animateTo diagonally in Compose and coroutineScope?

Time:05-02

I have a box that I drag over and around (was a struggle, but I realised that the Kotlin SDK is actually really good with lots of examples). now. I setup this box in a way that when it's clicks, and, or moved, it changes it size - it looks nice :).

Now, I wanted this box to get back to its original coordinate (for the time being it's 0,0 but, will change to some var in the future).

I am struggling with the diagonal movement. tried while loops, tried external functions, and a whole external class for calculating the smoother movement, but. even when I succeed to go forward a step, its performing so slow!! that I am starting to think that it's not the right way.

@Composable
fun drawText() {
    Box(
        modifier = Modifier
            .fillMaxSize()
    ) {
        val coroutineScope = rememberCoroutineScope()
        val enable = remember { mutableStateOf(true) }
        var offsetX  =  remember { Animatable(0f) }
        var offsetY  =  remember { Animatable(0f) }
        val interactionSource = remember { MutableInteractionSource() }
        val clickable = Modifier.clickable(
            interactionSource = interactionSource,
            indication = LocalIndication.current
        ) { }
        val isPressed by interactionSource.collectIsPressedAsState()
        val size = animateSizeAsState(
            targetValue = if (enable.value && !isPressed) {
                Size(50f, 50f)
            } else {
                Size(100f, 100f)
            }
        )
        Box(
            Modifier
                .offset { IntOffset(offsetX.value.roundToInt(), offsetY.value.roundToInt()) }
                .background(Color.Blue)
                .size(size.value.width.dp, size.value.height.dp)
                .pointerInput(Unit) {
                    detectDragGestures(
                        onDragStart = {
                            enable.value = !enable.value
                        },
                        onDrag = { change, dragAmount ->
                            change.consumeAllChanges()
                            coroutineScope.launch {
                                offsetX.snapTo(offsetX.value   dragAmount.x)
                                offsetY.snapTo(offsetY.value   dragAmount.y)
                            }
                            spring(stiffness = Spring.StiffnessHigh, visibilityThreshold = 0.1.dp)

                        },
                        onDragEnd = {
                            enable.value = !enable.value
                            spring(stiffness = Spring.StiffnessLow, visibilityThreshold = 0.1.dp)
                            coroutineScope.launch {
                                offsetY.animateTo(
                                    targetValue = 0f,
                                    animationSpec = tween(
                                        durationMillis = 1000,
                                        delayMillis = 0
                                    )
                                )
                                offsetX.animateTo(
                                    targetValue = 0f,
                                    animationSpec = tween(
                                        durationMillis = 1000,
                                        delayMillis = 0
                                    )
                                )
                            }
                        }
                    )
                }
                .then(clickable)
        )
    }
}

This code moves it first to 0 y and than to 0 x .. which is not the outcome I'm looking for

CodePudding user response:

animateTo is a suspend function, which means your X animation only will start when Y animation finishes.

You can launch an other coroutine to run them in parallel:

coroutineScope.launch {
    launch {
        offsetY.animateTo(
            targetValue = 0f,
            animationSpec = tween(
                durationMillis = 1000,
                delayMillis = 0
            )
        )
    }
    offsetX.animateTo(
        targetValue = 0f,
        animationSpec = tween(
            durationMillis = 1000,
            delayMillis = 0
        )
    )
}

An other option is animating the offset, instead of animating each parameter. Here's how you can use animatable with Offset:

val offset = remember { Animatable(Offset.Zero, Offset.VectorConverter) }

// onDrag: 
offset.snapTo(offset.value   dragAmount)

// onDragEnd:
offsetY.animateTo(
    targetValue = Offset.Zero,
    // ...
  • Related