Search code examples
fluttergeometryborderdraw

Flutter Draw a circle border with 3 multiple colors and values


How do you draw a diagram style circle border with multiple values? Also animated that each value in circle expands dynamically filling 100% of the circle?


Solution

  • Animation can be handled by TweenAnimationBuilder and it will be played on build. To achieve desired result we must use customPainter.

    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    import 'dart:math' as math;
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: MyHomePage(),
          debugShowCheckedModeBanner: false,
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: TweenAnimationBuilder(
              duration: const Duration(seconds: 2),
              tween: Tween(begin: 0.0, end: 1.0),
              curve: Curves.easeOutCubic,
              builder: (BuildContext context, dynamic value, Widget child) {
                return CustomPaint(
                  painter: OpenPainter(
                      totalQuestions: 300,
                      learned: 75,
                      notLearned: 75,
                      range: value),
                );
              },
            ),
          ),
        );
      }
    }
    
    class OpenPainter extends CustomPainter {
      final learned;
      final notLearned;
      final range;
      final totalQuestions;
      double pi = math.pi;
    
      OpenPainter({this.learned, this.totalQuestions, this.notLearned, this.range});
      @override
      void paint(Canvas canvas, Size size) {
        double strokeWidth = 7;
        Rect myRect = const Offset(-50.0, -50.0) & const Size(100.0, 100.0);
        
        var paint1 = Paint()
          ..color = Colors.red
          ..strokeWidth = strokeWidth
          ..style = PaintingStyle.stroke;
        var paint2 = Paint()
          ..color = Colors.green
          ..strokeWidth = strokeWidth
          ..style = PaintingStyle.stroke;
        var paint3 = Paint()
          ..color = Colors.yellow
          ..strokeWidth = strokeWidth
          ..style = PaintingStyle.stroke;
    
        double firstLineRadianStart = 0;
        double _unAnswered = (totalQuestions - notLearned - learned) * range / totalQuestions;
        double firstLineRadianEnd = (360 * _unAnswered) * math.pi / 180;
        canvas.drawArc(
            myRect, firstLineRadianStart, firstLineRadianEnd, false, paint1);
    
        double _learned = (learned) * range / totalQuestions;
        double secondLineRadianEnd = getRadians(_learned);
        canvas.drawArc(myRect, firstLineRadianEnd, secondLineRadianEnd, false, paint2);
        double _notLearned = (notLearned) * range / totalQuestions;
        double thirdLineRadianEnd = getRadians(_notLearned);
        canvas.drawArc(myRect, firstLineRadianEnd + secondLineRadianEnd, thirdLineRadianEnd, false, paint3);
    
        // drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint)
      }
    
      double getRadians(double value) {
        return (360 * value) * pi / 180;
      }
    
      @override
      bool shouldRepaint(CustomPainter oldDelegate) => true;
    }
    
    

    enter image description here Hopefully someone will find this helpfull :) Feel free to improve on this! Happy coding !