How to improve my animation and make it even (Jetpack Compose)?

Viewed 1454

I am trying to fire some Boxes regularly from bottom to top. I have almost managed to achieve this but for some reason my Boxes are not spaced evenly, as you can see from the gif. My feeling is that my code is not the best way to achieve what I am trying to do. Does anyone have any ideas?

Here is my code:

listOf(
        Color(0xffDFFF00),
        Color(0xffFFBF00),
        Color(0xffFF7F50),
        Color(0xffDE3163),
        Color(0xff9FE2BF),
        Color(0xff40E0D0),
        Color(0xff6495ED),
        Color(0xffCCCCFF),
    ).forEachIndexed { index, color ->
        val infiniteTransition = rememberInfiniteTransition()
        val positionState = infiniteTransition.animateFloat(
            initialValue = 0f,
            targetValue = 1f,
            animationSpec = infiniteRepeatable(
                animation = tween(
                    durationMillis = 2500,
                    delayMillis = delay,
                    easing = LinearEasing
                )
            )
        )
        delay += 1000
        val modifier = Modifier.offset(
            x = (maxWidth - tileSize),
            y = maxHeight - (maxHeight * positionState.value),
        )
       Box(
            modifier = modifier
                .size(tileSize)
                .clip(RoundedCornerShape(5.dp))
                .background(color = color)
        ) {
            Text(
                text = text,
                Modifier.align(Alignment.Center),
                style = TextStyle(fontWeight = FontWeight.Bold)
            )
        }

Here is the gif:

Uneven boxes

PS: Having now tried the accepted answer, it doesn't work as expected. Please see comment below. Thanks!

1 Answers

This is because the delay is also being repeated in the infiniteRepeatable. In other words, the animations that were 1000ms apart in the first iteration become 2000ms apart in the second iteration.

Non-repeating delays are not yet support in infinite transition. Here I would recommend using Animatable to achieved the staggered infinite animation.

...
forEachIndexed { index, color ->
    val positionAnimation = remember { Animatable(0f) }
    LaunchedEffect(positionAnimation) {
        delay(1000 * index) // this delay increases with the index
        launch {
            positionAnimation.animateTo(
                1f,
                animationSpec = infiniteRepeatable(
                    animation = tween(
                        durationMillis = 2500, // remove the delay from infinite repeatable
                        easing = LinearEasing
                    )
                )
            )
        }
     }
...

Related