Postman Loading Screen Animation

A lot of you guys must have used Postman before. Today, we are going to build the Postman loading screen animation, so let’s get straight into it.

We are going to break this animation down into three simple milestones —

Drawing the inner circle and the concentric circles. Placing (drawing) the small balls on each of the concentric circles. Finally, making the balls go crazy.

Milestone #1 — Drawing the circles

The easiest way to draw shapes in Flutter is by using the CustomPaint widget. Now, how to draw a circle using CustomPaint?

The CustomPaint takes a painter argument which is responsible for drawing a shape. A painter is implemented using the CustomPainter class. Looking up the documentation we find -

To implement a custom painter, either subclass or implement this interface to define your custom paint delegate. CustomPaint subclasses must implement the paint and shouldRepaint methods, and may optionally also implement the hitTest and shouldRebuildSemantics methods, and the semanticsBuilder getter.

Hence we blindly follow what the almighty documentation tells us to. We create a class and extend it to the CustomPainter and implement the required methods. It looks something like this -

As written in the documentation, the necessary methods are the paint and shouldRepaint methods. To understand how the paint methods work in simple words think of it like this, the paint method uses a Paint object to draw on the Canvas of a fixed Size . Let’s see it in action by following these steps —

Create a Paint object (which contains information regarding how to draw the shape for example the stroke type, stroke width etc) Choosing a fixed offset (which contains information regarding where to draw the shape in the canvas) Calling the draw function (which contains the information regarding what type of shape to draw for example circle, arc, line etc)

We finally have a circle on the screen.

Now let’s move on to building the rest of the concentric circles. If you observe carefully, the only difference between this circle and the other three concentric circles is that they differ in radius and are not color filled. Hence, we draw three more circles with different radii. The paintStyle property of the Paint object takes care of how you want to draw the circle. PaintStyle.stroke just outlines the shape and does not fill it. So we draw three more circles by making the following additions -

And now we have the circles to place our balls on.

Milestone #2 — Placing the small circles

This part is rather the easiest of all the three milestones. Creating a circle, filling it with a desired color and placing it at a specific position are the things we have learned till now. Here, we only have to create three identical circles and place them on the radii of the three concentric circles. The placement of these circles is a little tricky though. If you think hard enough, the path that the small circles will follow has the following logic—

x = size.width/2 + radiusOfPath * math.cos(initialDisplacement + rotationAngle * rotationSpeed)

y = size.height/2 + radiusOfPath * math.sin(initialDisplacement + rotationAngle * rotationSpeed)

where,

intialDisplacement is the angle from which we want to start the animation of rotation, rotationAngle is the angle of rotation at any given instant of time and rotationSpeed is the speed of rotation of the small circle around the inner circle. For now we’ll keep the initialDisplacement, rotationAngle and rotationSpeed to be zero, we’ll set them when we implement the third milestone.

Milestone #3 — Animating the circles

The thing that is left is making the circles rotate around the inner circle at different speeds. This can be achieved if we are able to change the values of rotationAngle at every instant. Hence, this makes a perfect case for using Tween Animations in Flutter. If you have any experience with the Tween animations you would know that Animation and AnimationController are the two key objects required to implement them. Using this Animation object we will change the value of the rotationAngle every instant. To pass the animation.value from the widget to the CustomPainter we will be using a rotationFactor variable. Our rotationAngle is now defined by the following logic —

rotationAngle = rotationFactor * math.pi

Another thing remaining is the speed at which the circles will be rotating. I have personally set the speed of the inner most circle to be twice of the middle circle which has twice the speed of the outermost circle.

Now comes the very last change. It is a very small change but indeed is a critical one. The shouldRepaint method returns false by default. We have to change it to true. The reason for this lies in understanding what the shouldRepaint method does. Essentially, all it does is, it controlls the rebuilding of the CustomPainter widget. In simpler terms, it is called whenever a new instance of the CustomPainter class is called. Hence, setting it true allows us to build a new CustomPainter every time we make a new instance. And we make are making a new instance for every new tick in the animation.value .

Here is the final code for the whole animation —