How to implement CircularRevealAnimation as Flutter widget and publish it on pub.dev on the way

Alexander Zhdanov
Flutter Community
Published in
4 min readMay 22, 2019

--

In Android, there is a very interesting Animation called CircularRevealAnimation. Flutter while have rich animation possibilities doesn’t provide this animation out of the box.

In this article, I’ll describe how to implement this animation using Flutter SDK and publish the library on pub.dev for easy access and distribution.

Animation implementation

Everything is a widget in Flutter. And animations aren’t exceptions. That’s why we need to create, extending StatelessWidget.

Animations control (start, pause, stop, etc.) is controlled by AnimationController. To createAnimationController we need to extend StatefulWidget and add a special class SingleTickerProviderStateMixin to State.

Our class CircularRevealAnimation will not control animation by itself. It will receive Animation<double> as a required constructor parameter. That’s why there is no need to extend StatefulWidget. This is done to allow combine CircularRevealAnimation with other animations using the same AnimationController. For example, to combine circular reveal animation with opacity animation.

Another important constructor parameter CircularRevealAnimation is child that will be animated (appear or disappear). In general, a lot of widgets in Flutter has achild parameter. These widgets allow changing behaviour, drawing or position of the child widget. Or to add animation, like CircularRevealAnimation does.

In addition, to define animation we need such parameters as a reveal centre and a minimum and maximum radius of the reveal. These parameters are not required and may be null. In such a case, default values will be used. The default reveals centre is widget’s centre. The default minimum radius is zero. And the default maximum radius is the distance from reveal centre to further widget’s vertex.

The algorithm for calculating the maximum radius by default is as follows. First, calculate the distance horizontally and vertically from the centre to the vertex furthest from the centre of the reveal, and then calculate the diagonal using the Pythagorean theorem.

static double calcMaxRadius(Size size, Offset center) {
final w = max(center.dx, size.width - center.dx);
final h = max(center.dy, size.height - center.dy);
return sqrt(w * w + h * h);
}

Now we need to implement clipping of child widget within the circle during the drawing. Class ClipPath will help us to do that. ClipPath allows clipping widget on an arbitrary template. Parameters of this widget are clipper (about it a little later) and child — the widget that must be clipped.

Parameter clipper of ClipPath defines the way of the clipping child widget. To define our own clipping template we create CircularRevealClipper extending CustomClipper<Path> and override method Path getClip(Size size). This method returns Path that defines the cutting area. In our case, this area is a circle with a given centre. To calculate the circle’s radius we need to know the current animation’s value. This value is passed to CircularRevealClipper as a fraction parameter. The calculation of a circle’s radius is performed using linear interpolation between the minimum and maximum radii.

After that, we can implement CircularRevealAnimation. To create animation it is useful to use AnimatedBuilder. AnimatedBuilder takesAnimation<double> and builder that is used to build a child widget taking the current animation’s value into account. In builder we create ClipPath and pass current animation’s value (fraction) toCircularRevealClipper.

class CircularRevealAnimation extends StatelessWidget {
...
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget _) {
return ClipPath(
clipper: CircularRevealClipper(
fraction: animation.value,
center: center,
minRadius: minRadius,
maxRadius: maxRadius,
),
child: this.child,
);
},
);
}
}

This completes the creation of CircularRevealAnimation. To use it we need to create StatefulWidget, AnimationController and pass AnimationController to CircularRevealAnimation. Gist with example.

Demo-app on GitHub.

Creating a library

To create Dart or Flutter library you need to add file pubspec.yaml to the same dir where lib folder with .dart files are located. This file contains the library’s description and info about authors and dependencies.

It is good practice to create a separated file to define public API. This file is located in the lib folder and contains the library’s name and list of files that need to be included in public API. All other .dart files are placed in src dir. This allows us to import the whole library using a single import expression and hide files that are not included in the public API. Content of this file:

library circular_reveal_animation;export 'package:circular_reveal_animation/src/circular_reveal_animation.dart';

You can find more details about creating Dart libraries here.

Publication to pub.dev

It’s very easy to publish the Dart library to pub.dev. All you need to do is run flutter packages pub publish from the root dir of your library. The publication is carried out on behalf of the Google account. That’s why during publication you will need to open a given link in the browser and log in to Google. Later you can publish library updates only using the same account that was used to publish the first version.

Before publication, it is recommended to check the correctness of the library using flutter packages pub publish --dry-run.

After executing the flutter packages pub publish, the library will immediately be available at pub.dev. And, as written in the documentation, “Publishing is forever” — later you can only upload new versions. Old versions will also be available.

Although the publication of the library looks simple, it can also have pitfalls. For example, when publishing the first version of circular_reveal_animation, I was deprived of several points in the rating because the library description was too short (in pubspec.yaml).

You can find more details about publishing Dart libraries here.

Finally, the library circular_reveal_animation on pub.dev and github.com.

Update: in version 1.0.6 added example for Flutter dialogs.

--

--