bruno.aybar
09/22/2020, 5:39 AMtransitions
and transitionDefinitions
for a sample app I'm working on.
I noticed that I was having the same issues over an over while handling multiple transitions. Basically, transition(toState = , initState = )
is a bit confusing at first try. It's great for a single animation that triggers immediately (i.e. the Rally app circular animation). However, it's easy for the state to get out of sync / to cause undesired transitions.
I thought it may only be me, but I've seen the same problem in a post someone did. If you deep dive in the implementation, you'll notice:
• Actual transitions work great. Really powerful API.
• Problems: a) first transition is triggered right away. b) weird validations to display content because animating state and actual state are out of sync.
With that I'm not trying to bash the author, of course, actually I had almost the exact same issues. Here I'm just pointing out a few ways in which I think the current API can be misused. There are solutions for those problems, yes, but I don't think they are that easy to figure out right now.
So after dealing with some animations, I spotted a pattern with my implementations. Basically I had:
• a class with the state. Same as in Jetsurvey app, which I used as example.
• within that state, hold a current
and animatingTo
states. They work as the source of truth for the transition.
That looked like the ideal solution for some of my transitions (not all of course, some work just fine without extra classes holding the state). Given that a lot of the logic was reused, I created a base implementation instead.
Now, my question is: is this the correct approach? I really don't want to reinvent the wheel, or complicate things with unnecessary logic.abstract class AnimationStateHolder<T>(initialState: T) {
/**
* Represents the current state of the animation. Its value won't change
* until the animation to a new state has been completed.
*/
var current by mutableStateOf(initialState)
private set
/**
* Represents the state to which we are transitioning to. If there is no transition
* occurring at the moment, then [animateTo] and [current] will have the same value.
*/
var animatingTo by mutableStateOf(initialState)
private set
fun animateTo(newState: T) {
if(newState != current) {
animatingTo = newState
}
}
fun onAnimationFinished() {
current = animatingTo
}
}
Doris Liu
09/22/2020, 6:02 AMinitState
is only needed if you need the animation to trigger as soon as the transition
composable is loaded. If you don't define initState
, the animation will always animate from where it currently is (i.e. could even be in between two states) to the new toState
, similar to what you suggested. 🙂toState
instead of both toState
and initState
, unless the intention is to start a brand new animation from initState
to toState
. As you change toState
(only), the default behavior is to internally remember
the current toState
and only change the animation's course when toState
has changed. In the meantime, all the animation values/velocities are tracked, so as to ensure fluidity when animation target (i.e. toState
) is changed amid animation.bruno.aybar
09/22/2020, 6:29 AMDoris Liu
09/22/2020, 6:36 AMTransitionState
?Yann Badoual
09/22/2020, 8:22 AMfromState
value in the TransitionState
could be useful in some cases, like chaining transitions like we discussed last time. Instead of having to manually provide a key to identify each "waypoint"