https://kotlinlang.org logo
#compose
Title
# compose
e

elye

02/18/2022, 8:33 AM
Hi All, do you know if the
UpdateTransition
animation being interupted half way, does it still retain its velocity for it’s subsequent animation (that interrupt it)? I think it should, as that’s what
AnimateAsState
and
Animatable
behave like. For more context, I provide a full code and some GIF animation to illustrate this clearer in https://stackoverflow.com/questions/71170430/will-updatetransition-animation-maintain-its-running-velocity-when-if-being-chan
Hi @Doris Liu, sorry to bother you again. I suspect this is Google bug, but I might be wrong. 🙏
d

Doris Liu

02/18/2022, 9:44 PM
No worries @elye. Thanks for reaching out.
Transition
does retain velocity when interrupted, as it switches to a spring under the hood to handle the interruption. See my reply to your question on StackOverflow for more details.
e

elye

02/19/2022, 4:25 AM
Thanks Doris. I see the
Transition
just use the
Spring
default animation when being interrupted, while the velocity is retained. I further experiment with
Keyframes
and
Snap
as as per your state in stackoverflow. I can implement it for to and fro with different animation spec for AnimationAsState and Animatable as below
Copy code
val dbAnimateAsState: Dp by animateDpAsState(
        targetValue = switch(enabled),
        animationSpec = if (enabled) keyframesSpec() else snapSpec()
    )
and
Copy code
dbAnimatable.animateTo(
            targetValue = switch(enabled),
            animationSpec = if (enabled) keyframesSpec() else snapSpec()
        )
And for transition, I use
Copy code
val dbTransition by transition.animateDp(
        transitionSpec = {
            if (targetState) {
                keyframesSpec()
            } else {
                snapSpec()
            }
        }, label = ""
    ) {
        switch(it)
    }
The Keyframes and Snapspot use as below
Copy code
private fun keyframesSpec(): KeyframesSpec<Dp> =
    keyframes {
        durationMillis = 5000
        0.dp at 0
        100.dp at 1000
        50.dp at 2000
        200.dp at 3000
        100.dp at 4000
    }

private fun snapSpec(): SnapSpec<Dp> =
    snap(2000)
When test it out, it works well for
AnimateAsState
and
Animatable
as per the GIF below. It looks odd, but at least it is honoring the animation Sec we defined I hope we can have
Transition
behave like
AnimateAsState
and
Animatable
d

Doris Liu

02/19/2022, 5:11 AM
Thanks for the investigation.🙂 Since there's no one-size-fits-all solution, it's best to make the interruption handling configurable. In terms of consistency,
Animatable
doesn't and shouldn't have an interruption handling logic aside from trying to preserve a continuous value and velocity if possible, as it is a very low level API. Users of the API have full control of what happens at the point of interruption. As for
animate*AsState
I agree with you that there's inconsistency between it and
Transition
. But I'm not convinced that the current behavior in
animateAsState
is better than falling back to a slower spring than what
Transition
uses currently. Note that
tween
and
keyfarmes
almost guarantee a discontinuity in velocity when interrupted. Therefore they aren't good choices for handling interruptions.
e

elye

02/19/2022, 5:44 AM
Thanks Doris. I see this code in
class Transition<S> @PublishedApi internal constructor
. I guess it’s by design.
Copy code
val spec = if (isInterrupted) {
                // When interrupted, use the default spring, unless the spec is also a spring.
                if (animationSpec is SpringSpec<*>) animationSpec else interruptionSpec
            } else {
                animationSpec
            }
And
Copy code
interruptionSpec = spring(visibilityThreshold = visibilityThreshold)
If we can have that configurable to have our own defined interruptionSpec, that will be great. Well, at least now I see the code, and clearly it’s by design. Thans for the explanation.
d

Doris Liu

02/19/2022, 5:46 AM
Yes, that was a deliberate decision. Though we are keeping the options open for potentially allowing customization on the interruption behavior.
👍 1
🙏 1
e

elye

02/19/2022, 5:47 AM
Ya, if we can have it set, or have it use the existing animationSpec that will help further. Thanks for the explanation 🙏
d

Doris Liu

02/19/2022, 5:50 AM
That interruptionSpec is likely too stiff. We have later found the
stiffnessMediumLow
to be more suitable as the default, instead of
stiffnessMedium
. Curious what prompted you to notice the difference? What was the use case?
e

elye

02/19/2022, 7:51 AM
Thanks for asking. How I get to know is, when I use
transition
animate something (e.g. expand something and shrink when the button click again), if I click half way the expanding through, the animation just suddenly return to its origin too quickly. Feels like no animation at all. If I let the animation (expand) finish and click again, then it shrink properly. So test out using
Animatable
and
AnimateAsState
, all is good, as the animation to and fro is retain even when interrupted. But
Transition
interruption makes it feel like the animation gone missing. I think it’s common for all case. It might not be noticeable if the animation happens quick (given the interrupt animation is also stiff and quick). But once we have a moderate animation, it can be sensed.
I think that if we change the default interrupt animation stiffeness to make the animation slower (less stiff) is also not ideal. In case if the animationSpec provided by the user is a fast one, then the interruption will produce a slower animation, which feels odd too. Hence, in my opinion, it’s best to use back the animationSpec provided by the user by default for the interupted animation, like what
Animatable
and
AnimateAsState
does.
d

Doris Liu

02/22/2022, 6:59 PM
Thanks for taking the time to investigate this and sharing your feedback, Elye. 🙂🙏 We'll make sure to make the interruption handling configurable as we build more support for Transition and other high level animation APIs.
e

elye

02/28/2022, 11:15 AM
Thanks @Doris Liu, that’s great. Looking forward for the interruption animations set can be customized (or used it’s original set animation set) Just a quick demo of a case. There’s a custom interpolator I have made (Perlin Noise interpolator). I make them as GIF below. When interrupted (mouse click), it will resume the Perlin Noise interpolation animation spec…. so all looks good throughout all the interruption (mouse click). I can do this with AnimationAsState, and Animatable, but not Transition as the Transition interruption will change to Spring.
👍 1
2 Views