2

I am currently developing an application using Kotlin and Jetpack Compose. My task is to create an animation where each letter in a given word alternately increases and decreases in size, creating a wave-like effect across the text. This means that one letter at a time will grow larger, then shrink back to its original size, before the next letter does the same. This pattern will repeat for each letter in the word.

Here is the relevant code:

@Preview(showBackground = true)
@Composable
fun AnimatedTextPreview()
{
    AnimatedText("Hello")
}

@Composable
fun AnimatedText(word: String) {
    val duration = 500L
    val delayPerItem = 100L
    val transition = rememberInfiniteTransition()

    Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
        word.forEachIndexed { index, c ->
            val scale by transition.animateFloat(
                initialValue = 1f,
                targetValue = 2f,
                animationSpec = infiniteRepeatable(
                    animation = tween(
                        durationMillis = duration.toInt(),
                        delayMillis = ((delayPerItem * index) % duration).toInt(),
                        easing = FastOutSlowInEasing
                    ),
                    repeatMode = RepeatMode.Reverse
                ), label = ""
            )
            Text(text = c.toString(), fontSize = (24 * scale).sp)
        }
    }
}

The animation sequence works as expected the first time, creating a wave effect as each letter increases and decreases. However, from the second time onwards, the letters start increasing and decreasing out of order, disrupting the animation. I suspect the issue might be with delayMillis.

I would appreciate any guidance on how to resolve this issue

1 Answer 1

1
+50

infiniteRepeatable repeats the animation along with the specified delay on each cycle, causing desynchronization after the initial cycle.

To avoid this, delay only the first iteration using initialStartOffset parameter:

animationSpec = infiniteRepeatable(
    animation = tween(
        durationMillis = duration.toInt(),
        easing = FastOutSlowInEasing
    ),
    repeatMode = RepeatMode.Reverse,
    initialStartOffset = StartOffset(offsetMillis = ((delayPerItem * index) % duration).toInt())
),

Note that your animation has to recompose one each frame, which may cause lags if your UI is complex. If you face such issue in release version of the app, you can draw letters on Canvas - measure each letter once with maximum font size(48.sp in this case), and scale/position them depending on animation state.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.