I need to pause and resume a `rememberInfiniteTran...
# compose
m
I need to pause and resume a
rememberInfiniteTransition()
, which looks to be impossible. What would be my alternative?
d
Could you share your use case?
m
I have a spinning image that should only be spinning when the user hovers their cursor over it.
e
animations are based on clock time so I don't imagine it being easy to pause and resume them
m
I was looking for something that could, maybe, let me change the rotation speed (between 0 and non-0).
e
well that can't really work either. given something that runs off of θ=t*dθ, changing dθ will completely change the current rotation, not just the speed
m
Hence why I'm here looking for pointers. 😄
e
Copy code
var isRunning by mutableBooleanStateOf(false)
val animation = Animatable(...)
if (isRunning) {
    LaunchedEffect {
        while (isActive) {
            animation.animateTo(360)
            animation.snapTo(0)
        }
    }
}
Spinner(angle = animation.value)
completely untested but perhaps something like that
m
That does animate when needed, but when
isRunning
becomes false it doesn't stop where it was, but resets. And when it runs again it starts from the beginning.
In other words, this stops and restarts the animation, not pauses and resumes like I need. 🤔
e
I didn't expect it to reset, the animation should be cancelled… possibly it's something inside AnimationState that's doing that
m
I guess I can save the current state when isRunning becomes false, and add a
snapTo(saved)
before the
animateTo()
e
or just use your own state,
Copy code
var angle by mutableFloatStateOf(0f)
LaunchedEffect {
    animation.snapTo(angle)
    while (isActive) {
        animation.animateTo(360) { angle = value }
        animation.snapTo(0)
m
Oh... Or I could just add
remember {}
around Animatable(), of course.
e
oh that should always be remembered, I just forgot to write it
m
Works perfectly now, thanks. 😄
Hmm, but the animationSpec is recreated each time. 🤔 So if the image does one rotation in 60 seconds, you stop hovering over it after it rotated 350°, then hover again, it will again take 60 seconds to complete the last 10°. In effect the animation slows down every time it's resumed.
Copy code
val animation = remember { Animatable(0f) }
val target = -360f
if (isHovered) {
    LaunchedEffect(Unit) {
        while (isActive) {
            val remaining = (target - animation.value) / target
            animation.animateTo(target, animationSpec = tween((60_000 * remaining).toInt(), easing = LinearEasing))
            animation.snapTo(0f)
        }
    }
}
Ok, this fixes it.
e
there might be a hack to go through
animateDecay
with a custom
FloatDecayAnimationSpec
. but that'll turn out to be the same math
186 Views