Physical Address

304 North Cardinal St.
Dorchester Center, MA 02124

flutter progress

How to implement circular percent indicator in Flutter

Creating a circular percent indicator in Flutter

There are multiple use cases which we will need to use the circle progress the application like fitness, habit etc to show progress.

You will learn how to implement the circle progress in Flutter within several minutes using CustomPaint widget and providing a custom implementation for CustomPainter class.

Application structures

Before jump into the coding, we need to think about the structure. In here we need to show the following things

  • Show Progress in Text
  • Show full circle which is represent a
  • background of the fill
  • Show Arc which shows the current Progress
  • Add animation when showing the progress

Custom circular percentage indicator

Inside the Scaffold body, Wrap our custom widget will allow showing progress in the centre of the screens.

Then you can provide CustomPaint as the child widget. In here you need to show the progress outside of the text widget. Therefore you need to pass CustomPainter widget as a foregroundPainter.

Then you need to create a CustomProgress. To Change the progress when the animation is happening we need to pass the progress to the widget.

As I mentioned above we have two circles to show the base of the progress and actual progress. For that, you need to create a two paint object to draw a Full Circle and a Draw an Arc. Check This Code.

class CircleProgress extends CustomPainter{

  double currentProgress;


  void paint(Canvas canvas, Size size) {

    //this is base circle
    Paint outerCircle = Paint()
        ..strokeWidth = 10
        ..color = = PaintingStyle.stroke;

    Paint completeArc = Paint()
      ..strokeWidth = 10
      ..color = Colors.redAccent = PaintingStyle.stroke
      ..strokeCap  = StrokeCap.round;

    Offset center = Offset(size.width/2, size.height/2);
    double radius = min(size.width/2,size.height/2) - 10;

    canvas.drawCircle(center, radius, outerCircle); // this draws main outer circle

    double angle = 2 * pi * (currentProgress/100);

    canvas.drawArc(Rect.fromCircle(center: center,radius: radius), -pi/2, angle, false, completeArc);

  bool shouldRepaint(CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return true;

Now the basic implementation is completed. Next we can add a animation to make this more cooool.

Add Animation when filling the progress

You can use tween animation to start from 0 and end in the percentage which you want to show on the progress. Then you can assign the current animation value to the text and you can pass that as a parameter to CircleProgress class.

class _CircleProgressState extends State with SingleTickerProviderStateMixin {

  AnimationController progressController;
  Animation animation;

  void initState() {
    // TODO: implement initState
    progressController = AnimationController(vsync: this,duration: Duration(milliseconds: 1000));
    animation = Tween(begin: 0,end: 80).animate(progressController)..addListener((){
      setState(() {


  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      body: Center(
        child: CustomPaint(

          foregroundPainter: CircleProgress(animation.value), // this will add custom painter after child
          child: Container(
            width: 200,
            height: 200,
            child: GestureDetector(
                onTap: (){
                  if(animation.value == 80){
                  }else {
                child: Center(child: Text("${animation.value.toInt()}%",style: TextStyle(
                  fontSize: 30,
                  fontWeight: FontWeight.bold