Building A Custom Page Load Animation in Flutter

A few weeks ago I shared a gif on my Twitter showing a really simple yet cool animation for a fictional app. The animation in question consists of two parts, the translation of elements from the bottom of the screen to their final position and the change in opacity as elements appear on the screen. In this article, I am going to cover how it was made.

Setup / Planning

Before we start coding, there are a few things we must consider. Let’s start by actually creating a new Flutter project and downloading the assets. If you are new, you can create a new Flutter project using the following command:

flutter create <your-awesome-project>

As for assets, we are going to need a header image. I chose a stock picture of New York from www.pexels.com.

Time to plan our animation. If we look at the gif, we immediately notice three distinct features:

The translation of the elements

Fade/Opacity

Timing

As you can see the different elements are using staggered animations, so that they fly in one after another.

Below is a timeline of the different animations:

From the image, we can clearly see the different animations and their associated time slots.

Before animating anything, let’s first define our static layout. The code below consist of basic theming and layout for our widgets. Running the code below will generate an image followed by dummy text and a button at the bottom of the screen.

With the main layout of our application defined, we can start working on the fun parts!

Setting up our Animation

There are a few different methods we can use to animate the app. The first and most obvious method would be to use an AnimationController. In our case, we're going to do something different, instead of setting up our own AnimationController, we are going to use the animation provided by the route. The reason for using the route animation is that it is automatically reversed when the user navigates to the previous page. A the user navigates to the page, the animation value goes from 0.0to 1.0. When they leave, the animation value goes from 1.0 to 0.0.

For this, there are two small addition we need to make to our existing code. First, in MaterialApp, we will use onGenerateRoute to return our app screen.

We check whether the route being pushed onto the Navigator is the first route. If it is the first route, we then call AnimationsPlayground.route();. This step is only necessary since we only have one page and would like to use our custom route. For a multi page application, we can simply use:

Navigator.of(context).push(AnimationsPlayground.route()).

To define our custom route, open AnimationsPlayground and add the following:

As you might have guessed, we are simply manually building the page with a custom transition duration (six seconds).

With our animation configured, we can move on to the next step, animating widgets!

Animating Widgets

Let’s start by defining our various animations. As we discussed earlier, there are three key steps this animation: translation, fade/opacity and timing.

The above snippet define animations for translation and opacity of our various widgets. Notice the difference in types, our translation Animation defines an Offset while our opacity and controller expects double.

Since we are using the animation provided by the route, we need to override didChangeDependencies so that the animation for the given ModalRoute may be accessed via the context. If you are wondering why we are not using initState(), it is because context is not available in initState().

If the controller variable we defined is null, the value from ModalRoute is used. Next we can start defining our Tweens. Let's start by defining the translation tween for the header image:

So what is going on here? We are using a Tween to specify a start and end value. We are then using a CurvedAnimation and an Interval to animate our Tween. The values passed to Interval represent the start and end percentage of the animation. Here, we are starting at 0.0s and ending at 67% or approximately 4 seconds into the total animation.

Now, we can define the remaining Tween:

With our Tweens now defined, the final step is to wire them to our static widgets. Let’s navigate to the build method of _CoolAnimatedAppState and wrap our Column in an AnimatedBuilder. Animated Builder requires an animation so for this we are going to pass it our controller variable. Next, we need to wrap our widgets in a widget which allows it to animate its position. There are many widgets we can use for this but to keep things simple, we are going to use FractionalTranslation. Fractional Translation moves it's child fractionally in relation to its parent. For example, if the parent defines a height of 200 pixel and you apply a 0.25 translation, then the child will be moved to 50 pixel or a quarter of the height of the parent.

The snippet above shows our widget tree with FractionalTranslation added. Note the value being passed for translation is the value of the corresponding variable (Tween). I refactored the three main components into their own StatelessWidgets to make the code a bit shorter and easier to read.

Last but not least is the fade animation. For this, we are again going to keep this relatively simple and use a FadeTransition. Let's update our code so that the child of our FractionalTranslation is a FadeTransition. Again we pass the corresponding Tween for the opacity value of our FadeTransition.

Now if we hot restart our app, we should hopefully see our animation!

Conclusion

Like I mentioned at the start of this article, there are many different ways this can be done. You don’t need to use the route animation if you don’t want to, you could’ve easily defined an AnimationController with a duration. My goal for this tutorial was to demonstrate how to build a really simple yet cool looking animation in a short space of time and with minimal effort. The advantage of using the animation provided by the ModalRoute is that it is automatically reversed when the user leaves the page, saving us the trouble of manually handling that scenario. If you’d like to learn more about Route animation, be sure to follow Flutter Community on Medium, we’ll have a more in depth guide to route animations sometime in the near future.

If you enjoyed this article, be sure to 👏 and share. If you’d like to see more cool apps and projects, be sure to follow Flutter Community and myself on Twitter. The final source code for this project is available on my GitHub at https://github.com/Nash0x7E2/page_load_animation.