In this blog, we demonstrate how Flutter’s animation API is designed to help developers create extremely complex to simple animations with absolute ease and what makes Flutter capable of supporting such smooth and high-level animations out of the box.
In this series of articles, we will deep dive into how animations work in Flutter. This three part series aims at providing an in-depth guide about what exactly happens under the hood when it comes to just about any type of animation in Flutter.
By the end of this series, you should be able to imagine what actually happens behind the scenes and thus readily get used to using the abstractions offered by Flutter, and any Flutter animations code you come across, it would no longer be a mystery of what all must be happening because of any piece of code.
Animation is all about updating the properties of a widget periodically at a certain speed.
If we look a bit deeper at what we mean by updating the properties of a widget periodically, we would want a mapping of what would be the value of the property after a given amount of time has elapsed, since the beginning of the animation ,i.e., we would want a function f which could be used to let us know what should be the value of the property of the widget when the function is provided with a certain elapsed time.
f : Elapsed time -> Property
Consider the height property of a widget that we want to update from 0px to 100px, over a duration of 5s.
Consider the following empty graph which represents Time (in seconds) on its X-axis, and Height (in pixels) on its Y-axis.
We could fill in the area of the empty graph with any curve of our choice.
The curve which we use determines how the height of the widget would change with time, which in turn determines how the animation effect would turn out to be. There could be infinitely many possible curves to fill this area of the empty graph.
Some of the many commonly used curves would be
I drew these curves by leveraging Flutter’s canvas API to illustrate several commonly used and popular curves available. These curves have been very commonly used when it comes to front-end animations, be it with CSS transitions or Flutter’s Curves.
These curves have been quite popular because they have been designed by taking inspiration from the nature around us and thus give a feel of realistic or natural animation effect to our human eyes.
If you consider for example the bounce-out curve from above, you would relate it well with an effect that comes when you release a ball from a certain height and let it undergo several bounces and finally rest on the ground.
There have been several experiments that studied specifically this particular effect on a ball when released from an initial height above the ground and let it bounce until it comes to rest. These experiments could study the variations in the height of the ball with time.
Below is a graph representing the changes in the height property of the ball from the ground, with elapsed time since the time the ball has been released.
I took the graph from an experiment’s research publication about the Aerodynamic Effects of a Dropped Ping-Pong Ball Experiment. If you take a closer look at the graph, it is conveying the same thing which I have been trying to address so far in this article. I am trying to map changes in the value of a widget’s property with elapsed time over a particular duration.
In the case of the ping-pong ball experiment, it was all the physics you could imagine, was playing its role in updating the height of the ball from the ground since it’s released till it comes to rest. When it comes to implementing something similar, it’s all about the curve function which we use to calculate the next value of the property when provided with a certain elapsed time value. Thus, the graph of the curve functions which you saw above is representing the different values of height at different instances of elapsed time, which would otherwise be produced by physics when applied to the ball.
Consider a widget that is a simple Container with color: Colors.black, and we would want to animate its height property from 0px to 100px over 5 seconds.
When we would update the height property following any of these curves over 5 seconds, we would get to see the effect of these curves.
Below is a demo I tried to implement using Flutter’s animations API and leveraging Flutter’s canvas API to illustrate different commonly used curves, to demonstrate what we mean when it comes to animating any widget’s property over a given duration, which is nothing but updating widget’s property at every instance of time throughout animation duration, using a particular curve which helps us to determine what should be the property of the widget after a given duration is elapsed so far.
To be able to keep on computing the widget’s property (height in our example) throughout the given animation duration (of 5s in our example), we would need to continuously keep track of elapsed time during the animation duration.
As and when there is a change in elapsed time since animation has started, we would need the next value of the widget’s property (height) to assign the widget’s property (height) with the same, thus in turn, updating the widget’s property (height) at every instance of change in elapsed time, which thus in turn appear as an animation effect to our human eyes.
Thus to get the next value of the widget’s property (height) at every instance of change in elapsed time, we would invoke the corresponding curve function we used for the animation, by providing the current elapsed time at that instance.
Thus, to think about implementing any animation, the whole point now boils down to two things:
After understanding what we need after all, to satisfy the human eye about if something’s animating, which is a fresh instance of elapsed time as and when it changes along with the curve, it makes it easier to think how one could achieve the same with flutter.
In the next two part, we will shift our focus to how Flutter approaches achieving these two things. To begin with, we will see what Flutter has to offer to be able to obtain the fresh instance of elapsed time, in the next blog.