Jetpack Compose way to animate Android Views
source link: https://proandroiddev.com/jetpack-compose-way-to-animate-android-views-f5ffe0344a0
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Jetpack Compose way to animate Android Views
In this article we will adopt animate*asState from Jetpack Compose for using with regular Android Views
Working with user interfaces sometimes is not an easy job. On Android you have a bunch of presentation layer architectural patterns like MVP, MVI, MVVM, which are managing a view in a slightly different manner.
But in the end you are just changing a view state, no matter what pattern you are using.
You might want to show or hide something, change color, height, scale or whatever else. The easiest way to do that is just set required value, then invalidate the view and on the next frame Android framework will try to re render your view tree.
There are actually some advantages of this approach:
- View tree is always in actual state as you not launching any transitions/animations. If for whatever reason you showed some view, but later in a 100ms you want to hide it — no problem, just call view.setVisibility(View.GONE) and that’s it.
- Easy and fast to develop/modify/maintain the code as you don’t need to carry about animations. For whatever input you get from your business logic you are just immediately change view state and everything working as expected.
Here is an example of the UI that is using this approach:
Note how chip change its background and text color instantly, without any animation. Probably a code to implement something similar would look like this:
Selectable chip view exampleInside of the bind(isSelected) method we are just changing internal properties of a text view depending on a boolean flag. So we might say that our view has 2 states: selected and not selected.
But what if we want to make this a bit more pleasant for the user?
We could at least try to add a color animation to change background and text color. A main point to take care of here is that the
animation must be cancelable and reversible
This means that if we are currently animating one tab, when another tab is selected we should be able to cancel animation on a first tab, animate it back to un selected state, while animating second tab to selected state. Therefore you should have some kind of animation state.
A Jetpack Compose can be inspiration for this. It introduced a bunch of animate*asState functions which are managing state of the animation internally.
Jetpack Compose animate color as state sampleWhen you update isSelected property this function will cancel current animation (if any) and animate from current animation state to target state with specific animation spec.
This is cool for compose based UI, but what with “legacy” android views? When adopting compose to your app not all screens can be refactored instantly and you might want to just modify existing view implementation.
Let’s try to achieve something similar with ValueAnimators.
AnimatedColor
An AnimatedColor class with animation state managing could look like this:
We will have a single public property called color, and an update callback. Update callback will be called immediately after creating this class to set initial color and later it will be called when animation is running. When new color will be set, AnimatedColor will check if this color is the same, if not it will start an animation.
Now the animation part. There will be a property called animator which will represent a current animator. And when the new target color value is set and animation triggered, we will
- get current color from the animation state
- cancel current running animator
- create a new animator which will animate previously retrieved color to target
- launch new animator
- call colorUpdatedCallback with new value retrieved from animation update
This is how we will create this animation from code:
As you see using this is pretty easy, you just assign a new target color to color property of AnimatedColor class and it will animate a color automatically. Also notice how AnimatedColor is storing current state of the animation and no additional work required. Here is current animation result:
I intentionally slowed down the animation speed so we can see that this animation is cancelable and reversible.
AnimatedValue
Actually we can abstract more and create more generic class for handling this. Instead of a color we will have a <T> generic value, and instead of creating new ValueAnimator each time we need to run animation, we can reuse existing animator.
And actually we don’t need to animate between a color values to animate color. We could just always animate between 0f and 1f with specified time and interpolation, and later just convert somehow this animated float value into <T>. And this “T” could be any type, it could be an Int representing a color, or Int representing a x coordinate of a view, we really don’t care. All we need is to evaluate a float between 0f and 1f into this “T”.
For this purposes Android animation framework provides us with TypeEvaluator<T>. This interface has only one method:
Evaluate method based on current animation fraction (float) and start and end values will return a value T. That’s what we need. And Android framework already provides us with few implementations of this TypeEvaluator. There are an ArgbEvaluator for evaluating colors, FloatEvaluator, IntEvaluator and a few others.
One last thing we need to solve is to store current state of animation. Our AnimatedValue class will have 3 fields:
- valueis needed for updating target state
- startValue is needed for storing startValue of a new animation when previous animation canceled
- currentValue represents current state of the animation
How all this are going to work:
For all animating values we could introduce a functions with using own evaluator just for convenience.
In terms of animation UI currently nothing changed. We still have our 60 fps smooth cancelable and reversible animation.
But what if we wanted to add something like animating a change of scale for currently selected tab? How difficult would that be? You are right! Easy-peasy.
With only few lines of code we again created cancelable state based animation.
A few other things that can be animated with this:
Hope you enjoyed the reading and will consider to apply this approach into your applications. As always all of the source code is available on GitHub. Cheers!
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK