A custom circular progress indicator with text, using custom painting and styled text
import 'dart:math';
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: const Scaffold(
body: Center(
child: CircularProgressWithText(8),
),
),
);
}
}
class CircularProgressWithText extends StatelessWidget {
final double percentage;
const CircularProgressWithText(this.percentage, {super.key});
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: _CircularProgressPainter(percentage),
child: Container(
width: 40,
height: 40,
alignment: Alignment.center,
child: OutlinedText('${percentage.toInt()}%'),
),
);
}
}
class _CircularProgressPainter extends CustomPainter {
final double percentage;
_CircularProgressPainter(this.percentage);
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..strokeWidth = 10
..color = Colors.blue
..style = PaintingStyle.stroke;
final center = Offset(size.width / 2, size.height / 2);
final radius = min(size.width / 2, size.height / 2);
canvas.drawCircle(center, radius, paint);
final progressPaint = Paint()
..strokeWidth = 10
..color = Colors.green
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round;
double arcAngle = 2 * pi * (percentage / 100);
canvas.drawArc(Rect.fromCircle(center: center, radius: radius), -pi / 2,
arcAngle, false, progressPaint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
class OutlinedText extends StatelessWidget {
final String text;
const OutlinedText(this.text, {super.key});
@override
Widget build(BuildContext context) {
final primaryColor = Colors.black.withOpacity(0.5);
final textStyle = TextStyle(
shadows: [
Shadow(
color: primaryColor,
blurRadius: 5,
offset: const Offset(0, 0),
)
],
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.bold,
);
return Stack(
alignment: Alignment.center,
children: [
Text(
text,
style: textStyle.copyWith(
foreground: Paint()
..style = PaintingStyle.stroke
..color = primaryColor
..strokeWidth = 2,
color: null,
),
),
Text(text, style: textStyle),
],
);
}
}