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

Mikael Alfredsson

01/13/2022, 6:07 PM
I have some issues with apring animations. I want to target a new random value when and one animation is finished. I do that by setting a new target in the finishedListener. When a new target is assigned, it jumps a little like it doesn’t really continues from the last target value. See code and results in the thread
Copy code
var target by remember { mutableStateOf(0.5f) }
val animTarget by animateFloatAsState(targetValue = target, animationSpec = spring(stiffness = 1f)) {
   target = Random.nextFloat()
}
LaunchedEffect(key1 = Unit) {
   target = Random.nextFloat()
}
Output : Look in the middle
d

Doris Liu

01/13/2022, 6:58 PM
That little bump upward in the middle of the graph that you shared is likely the end stretch of the previous animation, instead of in the beginning of a new animation. For spring animations, the values will get infinitely close to the target value over time, but will never reach the target. So there's a threshold that we need to set to consider the animation as "close enough" to the target and finish the animation. The default threshold for
animateFloatAsState
is 0.01f. You could tweak the
visibilityThreshold
param in
animateFloatAsState
to overwrite the default threshold. Note that the lower the threshold, the longer the animation is going to take to finish. Too large of a threshold would result in a visible jump in the end. The default thresholds are designed to avoid any noticeable visual jump (e.g. half a pixel). If you plot the animation value over time and really zoom in the graph, you will see that last bit of movement to close the gap once the threshold is met.
m

Mikael Alfredsson

01/13/2022, 7:00 PM
Shouldn’t a new target start from the “current” value and velocity independent of
visiblilityThreshold
?
d

Doris Liu

01/13/2022, 7:01 PM
Yes, the new animation started from the last target value. The jump happened before the end listener is invoked.
m

Mikael Alfredsson

01/13/2022, 7:02 PM
but if I don’t change the target, the animation wont jump at the end of the animation.
d

Doris Liu

01/13/2022, 7:03 PM
That threshold is only used when ending an animation. If you interrupt an unfinished animation, it should be perfectly smooth.
m

Mikael Alfredsson

01/13/2022, 7:05 PM
aha. now I get it, it jumps to the
target
value when the animation is as slow as the
visibilityThreshold
d

Doris Liu

01/13/2022, 7:06 PM
Yep, that's right. It jumps to the target when the animation is slow enough and close enough to the target.
m

Mikael Alfredsson

01/13/2022, 7:09 PM
nice, so the simple solution would be not not change the target on finish, but on a timer instead.. (and have a very low visibilityThreshold) This is just to move things randomly on the screen 🙂
d

Doris Liu

01/13/2022, 7:16 PM
Out of curiosity, do you see the jump visually? If so, there's probably a more than 100x multiplier going from animation value -> pixel. Definitely lower the threshold if that's the case. That's exactly why the threshold is customizable, as there's no one-size-fits-all value for the threshold. It's very much dependent on what the value represents. Lowering the threshold itself might be enough for your use case of moving things randomly on screen. If you prefer to change target before the animation ends, you could have a logic that changes target when the absolute delta is under say 0.1f.
m

Mikael Alfredsson

01/13/2022, 7:19 PM
I rotate a dot around a circle, and i decided to convert angles to %, so when I moved from 0f to 1f it moved one full revolution, and yes thats quite visible, thats why I checked with the graph to verify that I didn’t have a frame rate issue
the circle has a radius of 50dp
d

Doris Liu

01/13/2022, 7:28 PM
50dp is ~150 pixels assuming a density of 3. The default threshold is 0.1dp, and 0.5 for pixel. See: ;https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/[…]otlin/androidx/compose/animation/core/VisibilityThresholds.kt
m

Mikael Alfredsson

01/13/2022, 7:34 PM
thanks. I just didn’t realised it jumped to the target value, but that makes sense now when I think about it.
👍 1