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

bruno.aybar

09/22/2020, 5:39 AM
Hello! I’ve been playing with
transitions
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.
here's the app with that implementation
🎉 2
and here's the code I mention at the end:
Copy code
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
    }

}
d

Doris Liu

09/22/2020, 6:02 AM
initState
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. 🙂
I would recommend only altering
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.
b

bruno.aybar

09/22/2020, 6:29 AM
Right! And it works great for the transition itself. But let's say that: - you have an state - you create a transition with that state - you have inner content that changes based on the current state (this means, changes in actual components, not just properties of a single component) The toState from the transition can get out of sync with the actual state. Sorry if that's not clear enough... I can't explain it that well because I don't understand it that much myself. But that's something I've seen in at least 3 implementations out there in the internet. One example is the linked post, where if you check the button content, it's actually validating against the opposite state it should, because the transition toState and the actual state do not match.
But yes, if there is only 1 component involved in the transition, just toState works perfectly as you mention
(thanks for your explanation btw, and sorry if I'm not making sense, it's perfectly possible as my brain does no work well at this time 😅 )
d

Doris Liu

09/22/2020, 6:36 AM
No worries. I could barely think this time of the day also.😅 If I understand you correctly, by "the actual state", you meant the state that the animation is running from?
Would it be useful if we provided the "fromState" for the ongoing animation in the returned
TransitionState
?
y

Yann Badoual

09/22/2020, 8:22 AM
I think having the
fromState
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"
👍 2
2 Views