Flutter Explicit Animations | Master Flutter animations (part 2)

Santos Enoque
7 min readOct 27, 2021

--

In the first part of this article, we had an introduction to animations in Flutter, in part one we only talked about implicit animations, and if you read that article, you know that even though implicit animations are easier to implement, they limit the control we can have over the animation, that's exactly why we have explicit animations, they are relatively more difficult compared to the implicit counterparts but they give you total control over the animation, this article will get you up to speed with explicit animations in flutter.

Now, before we start I would like to add that this article is totally based on the official documentation, which you can check out here, now if you are ready let's start writing some code…

Initial Code

Let’s imagine that you are an intern at a development startup, and your first task is to build a loading screen for a taxi app the team is working on, the loading screen is pretty simple, the want a small car icon that moves back and forward (easy right?), so you come up with this code.

What we are doing in the code above is, we are using a periodic timer, and every second, we are changing the distance traveled by the car, if the distance is 0, we change it to 300, and if it is 300 we change it back to 0… well… the only problem here is that this animation looks choppy and natural and that's mostly due to the low frame-rate, whats a frame rate you ask?

Frames and Framerates

To understand frames and framerates you first have to understand how animations work in general, an animation is basically an illusion of movement that is created by displaying a sequence of images (frames) in a short span of time, so a frame would be a single image displayed in that sequence of images, and the framerate is the number of frames that are displayed every second denoted by fps (frames-per-second), so when we say flutter uses 60 fps (60 frames per second), we mean that under normal circumstances a flutter app will display 60 images every second, or you could say that the widget tree is rebuilt 60 times every second.

Improving the initial code

The animation we created at the top is choppy and unnatural, one thing that you may try to do to fix that is to reduce the duration of the periodic timer, and instead of changing the distance traveled from 0 to 300, you can gradually increment the distance traveled, to do that we will replace the code above with this new code.

Now, this looks way better right? The animation looks smoother and we can all go how right? WRONG! Even though this approach does in fact look better, there are still major drawbacks of this approach.

  • First, by using a Timer to animate our flutter apps, there’s no way of telling for sure if our animation runs at 60fps, we don't know if we are animating through every frame.
  • We had to interpolate between the range of 0 to 300 manually, which is less than ideal.
  • Now, the car that we are animating only moves forward, we would have to add a lot of code to make the car reverse.
  • We have no way of stoping the animation once it starts, and so much more…

That's why now, I will show you how to animate the correct way.

AnimationController

The AnimationController is a special Animation object that generates a new value whenever the hardware is ready for a new frame. All explicit animations require an AnimationController.

AnimatedController will create an interpolation of values between the upper and lower bounds, based on all of the possible frames for the given animation, what that means is that with an animation controller we would not have to manually create an interpolation of values, you only tell it that you want to animate between let's say 0 and 100 in one second and the controller will take care of everything (that's is awesome right?), AnimationController is playable, that basically means that we can start the animation, stop it, forward and reverse the animation.

Tickers and TickerProvider

In flutter, a Ticker is a class that does something (calls a callback function) on every new frame, by default Tickers start muted and we have to manually start them, a TickerProvider is an interface implemented by classes that wish to do something every time a new frame triggers, a TickerProvider, does exactly what its name suggests it provides a Ticker, and this is exactly what we need when we create explicit animations, previously we animated with the aid of a periodic timer, but that's not what we want, we want to create animations based on frames and not on a fixed time, and that's why from now on we will use TickerProvider instead of a periodic timer.

Vsync

AnimationController, takes an argument called vsync, vsync is used to “tell flutter if an object is being displayed on the screen”, this is useful because if the widget is not visible, then flutter will not animate that particular widget.

vsync must implement a TickerProvider interface. Therefore, the first step for creating an explicit animation is to make a TickerProvider object available to pass as the vsync argument to AnimationController. To do this, use a TickerProvider mixin with the widget that you are animating.

The only thing, that you have to do, is to add SingleTickerProviderStateMixin or TickerProviderStateMixin (when animating multiple widgets) to the state of the widget

Let’s animate the right way

First, let's add an animation controller and remove the other variables, and secondly, we will add a dispose method to make sure that all resources used by the animation controller will be freed once the widget is disposed.

The AnimationController is defined using the late keyword because it will be initialized after its declared, so basically, we are telling flutter that the controller, is null at the declaration stage but it will be initialized later (before it's used).

AnimationController(vsync: this): here we are passing _CarAnimationScreenState, as the TickerProvider argument vsync, we are able to pass _CarAnimationScreenState as a TickerProvider, because _CarAnimationScreenState implements SingleTickerProviderMixin

controller..dispose(): will dispose the animation controller when the widget is closed.

Now let's pass more arguments to the AnimationController

Line 1, represents the duration of the animation, in our case, is one second, lines 2 and 3, represent the bounds of the range of values that we wish to interpolate through.

An AnimationController doesn’t know anything about the UI—it merely triggers changes to its value property over a specified duration. To make your UI respond to the changes that AnimationController makes to its value property, register a listener with AnimationController that calls setState() each time AnimationController changes its value:

And since we removed the distance variable, we will use controller.value, to change the position of the car.

AnimationController provides an addListener() method that takes a callback function. AnimationController invokes this callback function every time AnimationController changes its value property. In order to rebuild the widget tree to reflect each change in AnimationController’s value property, you must call setState() from within the listener callback that you pass to addListener(). This is why explicit animations require StatefulWidgets.

Animation Triggers

The AnimationController comes with several methods that can be used to trigger the animation, those methods are:

  • forward() this method is used to start the animation from the lower bound to the upper bound, on our specific example that would mean moving the car from 0 to 300
  • reverse() this method is used to “play the animation backwards”, in our example that would be moving the car from 300 to 0
  • stop() used to stop the animation
  • repeat() this method is used to play the animation in a loop, it as a boolean parameter called reverse that is set to true the animation will animate forward and backwards and is set to false the animation will animate in a forward-only loop, in our example that would mean moving the car from 0 to 300, and then from 0 to 300 again without never moving it from 300 to 0
  • reset() resets the values of the property value, to the lower bound. “restarts the animation”

Now let’s add a few buttons to our app and see these methods in action

From lines 2 to 12 we are adding ElevatedButton widgets that will move the car forward, reverse it and stop it, and on line 19 we are adding another button that will loop the movement animation, notice this line here controller.repeat(reverse:true) here we have the value of reverse set to true because we want to move the can forward and in reverse as well, here is the final code and the resulting output

🎉 You Made It!

Congratulations to you if you made it this far, by now I really believe that you are more than ready to dive deeper into explicit animations using flutter, and I really hope this article was helpful to you… and if you liked the articles you probably will like my youtube channel 😉 and my github!

--

--

Santos Enoque
Santos Enoque

Written by Santos Enoque

Flutter developer & ML enthusiast

No responses yet