```val scale by animateFloatAsState( targetVal...
# compose
d
Copy code
val scale by animateFloatAsState(
    targetValue = when {
        badgeText.isNullOrBlank() -> 0f
        else -> 1f
    },
        animationSpec = spring(
        dampingRatio = Spring.DampingRatioMediumBouncy
    )
)
This makes my badge jump a bit with an animation when a new badge is shown on my icon. I also want to make it bounce a bit when it changes value (ex. badgeText "1" -> "2"), say bounce to 1.2f scale and than back to 1f. What's the best way to cause this nudge? I suppose I have to use a
LaunchEffect
but than I do not know how to nudge the scale value in an efficient way, thanks in advance for any answer
a
@Doris Liu
d
The best way to go about this is using Animatable:
Copy code
val scale = remember { Animatable(1f) }
            LaunchedEffect(key1 = foo) {
                scale.animateTo(1.2f, spring(...))
                scale.animateTo(1f, spring(...))
            }
animateFooAsState
anticipates different target values for different states. That's not really the case here where the (post-animation) target scale is the same for all states.
Animatable
is one level below animateFooAsState in the animation system and will therefore give you the control you need (see the diagram here: https://developer.android.com/jetpack/compose/animation#low-level-apis)
d
Thanks @Doris Liu I'll try tomorrow at work!
Thank you @Doris Liu it does work better
Copy code
val scaleAnimSpec = remember {
            spring<Float>(dampingRatio = Spring.DampingRatioMediumBouncy)
        }
        val scaleAnimatable = remember {
            Animatable(if (badgeText.isNullOrBlank()) 0f else 1f)
        }
        val scale = scaleAnimatable.value
        LaunchedEffect(badgeText) {
            val newTarget = if (badgeText.isNullOrBlank()) 0f else 1f
            val previousTarget = scaleAnimatable.targetValue
            val nudge = !scaleAnimatable.isRunning
                && newTarget == 1f && previousTarget == newTarget
            if (nudge) {
                scaleAnimatable.animateTo(1.2f, scaleAnimSpec)
            }
            scaleAnimatable.animateTo(newTarget, scaleAnimSpec)
        }
But it kinda surprised me, I though that
animateTo
would cancel the previous animation but it looks like it does not? I was expecting having to do
Copy code
scaleAnimatable.animateTo(1f, scaleAnimSpec, initialVelocity = 1f)
or something like that to nudge it from 1 and back (actually tried but it had no effect) May you clarify how is the internal behavior? thank you
d
animateTo
does cancel the previous animation. Your understanding is correct. 🙂 However, in the LaunchedEffect above, the two animateTo calls are a part of the same coroutine.
animateTo
doesn't return until the animation has finished. So by calling one animateTo after another, you essentially get a sequential animation.
d
I didn't realize it didn't return right away, that makes sense, thanks