Flutter tutorials and courses by Andrea Bizzotto

Flutter: Animated Task Completion Ring with AnimationController and AnimatedBuilder

This is a free lesson from my Flutter Animations course, where you'll learn how to build a completely custom habit tracking app.

In the previous lesson we have learned how to draw a "static" task completion ring:

Task Completion Ring Animation

But our goal is to bring this to life with some animations:

Task Completion Ring animation

Enter AnimationController

The animation above can be started, stopped, and reset to its initial value, and is known as an explicit animation.

And in Flutter, we use an AnimationController to create explicit animations. This video explains how:

Introduction to explicit animations with AnimationController. Full lesson here

TL;DR: Here's how to create and configure an AnimationController:

// 1. Create a StatefulWidget class AnimatedTask extends StatefulWidget { @override _AnimatedTaskState createState() => _AnimatedTaskState(); } class _AnimatedTaskState extends State<AnimatedTask> // 2. Add SingleTickerProviderStateMixin with SingleTickerProviderStateMixin { // 3. Declare an AnimationController late final AnimationController _animationController; @override void initState() { super.initState(); // 4. Initialize it _animationController = AnimationController( vsync: this, duration: Duration(milliseconds: 750), ); } @override void dispose() { // 5. Dispose it _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { // TODO: Use the AnimationController's value to set the progress: return TaskCompletionRing( progress: 0.6, ); } }

Setting up an AnimationController requires a lot of boilerplate code. This gets quite repetitive if you have a lot of widgets with explicit animations. This tutorial offers two possible solutions: How to reduce AnimationController boilerplate code: Flutter Hooks vs extending the State class.

Completing the animation code

Once we have created an AnimationController, we need to use it in the build() method. This lesson covers all the details:

Animated task completion ring with AnimationController and AnimatedBuilder. Full lesson here

Here's the completed code:

// 1. Create a StatefulWidget class AnimatedTask extends StatefulWidget { @override _AnimatedTaskState createState() => _AnimatedTaskState(); } class _AnimatedTaskState extends State<AnimatedTask> // 2. Add SingleTickerProviderStateMixin with SingleTickerProviderStateMixin { // 3. Declare an AnimationController late final AnimationController _animationController; @override void initState() { super.initState(); // 4. Initialize it _animationController = AnimationController( vsync: this, duration: Duration(milliseconds: 750), ); // 5. Forward the animation _animationController.forward(); } @override void dispose() { // 6. Dispose it _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { // 7. return an AnimatedBuilder return AnimatedBuilder( // 8. pass the AnimationController as an input animation: _animationController, builder: (BuildContext context, Widget? child) { // 9. Return a widget that is configured // with the AnimationController's value return TaskCompletionRing( progress: _animationController.value, ); }, ); } }

This code works and makes the animation start programmatically every time we hot-restart:

Task Completion Ring animation on hot-restart

But what we really want is to make things interactive, so that the animation can be triggered by the user.

And this is covered in my Flutter Animations Course. 👇

Flutter Animations Course

If you're serious about animations and want to learn how to use them in a real-world app, check out my complete Flutter Animations course.

This will teach you how to build a habit-tracking application with completely custom UI and animations. And it includes 7 hours of in-depth content, full source code, extra challenges & much more.

Flutter Animations Course
Flutter Animations Masterclass. View Course

Happy coding!

Want more?

Fast-track your Flutter learning with over 40 hours of in-depth content.