How to implement a custom loading animation in Flutter

“Flutter makes it easy and fast to build beautiful mobile apps” . So let’s put this to the test by creating a custom loading animation 🙂

Of course, Flutter provides a widget for Material Design progress indicator,  but let’s create something a bit more custom. How about 4 circles of different colours, growing in size and rotating?

For this code tutorial, we’ll create an app with one screen. When it starts, it simulates loading data, and while it does, a custom animation is shown. When the data is loaded, the animation stops.

Setting up the app

To follow the code tutorial, create a new app as follows.

If you’re unsure how to set up a Flutter app, check out Getting started with Flutter official tutorial.

Firstly, we create a Material app in main.dart, which will launch the HomePage widget.

 

Secondly, we create home_page.dart. This displays a Text saying the data is loaded, or a loading animation, depending on its state. For now, the loading animation is a CircularProgressIndicator: this will be replaced with the custom animation in the next section.

 

Lastly, let’s simulate loading the data. This is an async operation so we’ll use a Future. As it’s a simulation, we’ll simply use a Delayed future of 5 seconds.

Creating the animation

The animation is centred on the screen. It consists of 4 circles of different colours. They start small then grow in size. As they grow, they also rotate. Once the animation is completed, it runs in reverse, then in forward again and so on, until the animation is stopped.

Animations are orchestrated with SingleTickerProviderStateMixin and are made up of 2 objects: 1 AnimationController and at least 1 Animation value. The controller allows you to start the animation, forward or in reverse. It also has a duration for the animation. The Animation object holds the current value, which changes over time between 0.0 and 1.0 . This is this value that you use when creating your layout. It can be a double, but other types too, such as Color. It also has a listener for when the animation has reached the end. The way this value changes can be linear, curved etc. This value may change from x to y, instead of 0.0 to 1.0, by using a Tween.

Sounds confusing? Let’s amend home_page.dart with a 2 seconds animation. We will use 2 Animation objects, both of type double. The first represents an angle, from 0 to 360, and the second a scale factor, from 1 to 6.

 

Next, we’ll replace the CircularProgressIndicator with a custom UI, using the values from _angleAnimation and _scaleAnimation. It consists of 2 rows containing 2 circles each. All circles have the same size, and it depends on _scaleAnimation value. Then the 4 circles are rotated, using Transform.rotate, and the angle depends on _angleAnimation value.

 

And… that’s done! Pretty simple, no?

Note: just because such an animation is easy to do, it doesn’t mean you should start populating your app with custom loading animations! IMHO, their place is for an initial account sync. After that, your app should display cached data while getting the new one, and use platform UI conventions for refreshing as much as possible (eg pull down to refresh).

Voila

Custom loading animation
Custom loading animation

What next?

We used Row and Column to build the layout for the circles in this tutorial. For a reminder of how they work, check out “Flutter UI code tutorial: mastering Row and Column”.

 
 

Enjoyed this code tutorial? Support the blog!


Support options



 

Android app developer with 8 years experience, ranging from start ups to large tech (Google) and non tech (British Airways) companies. Currently freelancing and learning Flutter. LinkedIn natalie ( at ) cogitas (dot) net

Author: Natalie Masse Hooper

Android app developer with 8 years experience, ranging from start ups to large tech (Google) and non tech (British Airways) companies. Currently freelancing and learning Flutter. LinkedIn natalie ( at ) cogitas (dot) net

Leave a Reply

Your email address will not be published. Required fields are marked *