In this article, I will be building a count down timer with the help of the animation and using custom paint.

First of all, create an app which returns the MaterialApp.

Now create a new Widget CountDownTimer and make sure that it must be a Stateful Widget because we are using animation and we will need to add TickerProviderStateMixen .

class CountDownTimer extends StatefulWidget {

@override

_CountDownTimerState createState() => _CountDownTimerState();

}



class _CountDownTimerState extends State<CountDownTimer>

with TickerProviderStateMixin {

}

Create an Animation Controller

Create an animation controller and initialise it in initState() .

AnimationController controller;



@override

void initState() {

super.initState();

controller = AnimationController(

vsync: this,

duration: Duration(seconds: 5),

);

}

I am right now using only 5-second duration for my animation to happen.

Create a Circular progress bar using Custom paint

Create a class which extends CustomPainter

class CustomTimerPainter extends CustomPainter

Add properties

Now we will need some properties so we can customize my custom painter class from my widgets screen.

class CustomTimerPainter extends CustomPainter {

CustomTimerPainter({

this.animation,

this.backgroundColor,

this.color,

}) : super(repaint: animation);



final Animation<double> animation;

final Color backgroundColor, color;

}

I am using background color and color property for my Circular progress bar and to animate my progress bar, I will need an animation.

Override methods

We will override our paint method which will use to paint our circular progress bar.

First, we will paint a circle and we will create an arc will move around the circle.

In the paint method, create a Paint object and add properties.

Paint paint = Paint()

..color = backgroundColor

..strokeWidth = 10.0

..strokeCap = StrokeCap.butt

..style = PaintingStyle.stroke;

Now draw a circle

canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint);

When the circle is painted then will need to draw an arc to move.

paint.color = color;

double progress = (1.0 - animation.value) * 2 * math.pi;

canvas.drawArc(Offset.zero & size, math.pi * 1.5, -progress, false, paint);

Change the color of the paint and update the process using the current animation value and draw the arc.

Now we also have an override method shouldRepaint .

@override

bool shouldRepaint(CustomTimerPainter old) {

return animation.value != old.animation.value ||

color != old.color ||

backgroundColor != old.backgroundColor;

}

Here is the code for the CustomTimerPainter class

Create the UI

To animate my Custom Progress bar we will wrap my an AnimatedBuilder and provide the animation and it returns a CustomPaint Widget. When My animation will start the value of the arc will update in the custom painter class and update the UI

AnimatedBuilder(

animation: controller,

builder:

(BuildContext context, Widget child) {

return CustomPaint(

painter: CustomTimerPainter(

animation: controller,

backgroundColor: Colors.white,

color: themeData.indicatorColor,

));

},

),

And to start and pause the animation Ill use the Floating Action Button, we have also Wrapped my FAB with AnimatedBuilder so we can update my play and pause status.

AnimatedBuilder(

animation: controller,

builder: (context, child) {

return FloatingActionButton.extended(

onPressed: () {

if (controller.isAnimating)

controller.stop();

else {

controller.reverse(

from: controller.value == 0.0

? 1.0

: controller.value);

}

},

icon: Icon(controller.isAnimating

? Icons.pause

: Icons.play_arrow),

label: Text(

controller.isAnimating ? "Pause" : "Play"));

}),

Now if we see the app, it will look like this

Now Wrap the CustomTimerPainter inside the Stack and add text to represent the value.

To convert the animation duration into time String.

String get timerString {

Duration duration = controller.duration * controller.value;

return '${duration.inMinutes}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}';

}

Here is the code of CountDownTimer Widget

I have wrapped the root body widget and added a new Container and animating with animation value.

Container(

color: Colors.amber,

height:

controller.value * MediaQuery.of(context).size.height,

),

Here this complete code