Flutter Custom Circular Progress Indicator

This snippet showcases how to create a custom circular progress indicator in a Flutter application. It includes the setup of a basic Flutter app structure and an animated circular progress widget.
mail@pastecode.io avatar
unknown
dart
15 days ago
3.3 kB
1
Indexable
Never
// ignore_for_file: prefer_const_constructors

import 'dart:math';
import 'package:flutter/material.dart';

void main() {
  runApp(InitialScreen());
}

class InitialScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: CustomCircularProgressWidget(),
        ),
      ),
    );
  }
}

class CustomCircularProgressWidget extends StatefulWidget {
  @override
  _CustomCircularProgressWidgetState createState() =>
      _CustomCircularProgressWidgetState();
}

class _CustomCircularProgressWidgetState
    extends State<CustomCircularProgressWidget>
    with SingleTickerProviderStateMixin {
  late AnimationController _animationController;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    _animationController =
        AnimationController(vsync: this, duration: Duration(seconds: 5));

    _animation =
        Tween<double>(begin: 0.0, end: 1.0).animate(_animationController)
          ..addListener(() {
            setState(() {});
          });

    _animationController.forward();
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: CircularProgressPainter(
        progress: _animation.value,
        filledColor: Colors.purple,
        unfilledColor: Colors.purpleAccent,
      ),
      child: SizedBox(
        width: 350,
        height: 350,
      ),
    );
  }
}

class CircularProgressPainter extends CustomPainter {
  final double progress;
  final Color filledColor;
  final Color unfilledColor;

  CircularProgressPainter({
    required this.progress,
    required this.filledColor,
    required this.unfilledColor,
  });

  @override
  void paint(Canvas canvas, Size size) {
    double radius = min(size.width / 2, size.height / 2);
    Offset center = Offset(size.width / 2, size.height / 2);

    final filledPaint = Paint()
      ..color = filledColor
      ..style = PaintingStyle.stroke
      ..strokeWidth = 8.0;

    final unfilledPaint = Paint()
      ..color = unfilledColor
      ..style = PaintingStyle.stroke
      ..strokeWidth = 8.0;

    double startAngle = -pi / 2;
    double sweepAngle = 2 * pi * progress;
    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      startAngle,
      sweepAngle,
      false,
      filledPaint,
    );

    double dashWidth = 5;
    double dashSpace = 5;
    double circumference = 2 * pi * radius;
    double dashCount =
        (circumference / (dashWidth + dashSpace)).floor().toDouble();
    double dashAngle = 2 * pi / dashCount;

    for (double i = 0; i < dashCount; i++) {
      double currentAngle = startAngle + (i * dashAngle);
      canvas.drawArc(
        Rect.fromCircle(center: center, radius: radius),
        currentAngle,
        dashWidth / radius,
        false,
        unfilledPaint,
      );
    }
  }

  @override
  bool shouldRepaint(CircularProgressPainter oldDelegate) {
    return oldDelegate.progress != progress;
  }
}
Leave a Comment