Last active
February 13, 2025 15:27
-
-
Save tejaswini-dev-techie/3e8991d4d09394f3f9a55f0db451d350 to your computer and use it in GitHub Desktop.
A custom progress bar with a linear fill and dynamic step positioning.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'package:flutter/material.dart'; | |
| import 'dart:ui' as ui; | |
| void main() { | |
| runApp(const MyApp()); | |
| } | |
| class MyApp extends StatelessWidget { | |
| const MyApp({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return MaterialApp( | |
| debugShowCheckedModeBanner: false, | |
| home: Scaffold( | |
| body: Center( | |
| child: CustomPaint( | |
| size: const Size(328, 12), | |
| painter: | |
| StepperCustomPainter(filledRounds: 3, totalSteps: 5), // Dynamic steps | |
| ), | |
| ), | |
| ), | |
| ); | |
| } | |
| } | |
| class StepperCustomPainter extends CustomPainter { | |
| final int filledRounds; | |
| final int totalSteps; | |
| StepperCustomPainter({required this.filledRounds, required this.totalSteps}); | |
| @override | |
| void paint(Canvas canvas, Size size) { | |
| // Background progress bar | |
| Paint backgroundPaint = Paint()..style = PaintingStyle.fill; | |
| backgroundPaint.color = const Color(0xffE9E5EF); | |
| canvas.drawRRect( | |
| RRect.fromRectAndCorners( | |
| Rect.fromLTWH(0, size.height * 0.25, size.width, size.height * 0.5), | |
| bottomRight: Radius.circular(size.width * 0.009), | |
| bottomLeft: Radius.circular(size.width * 0.009), | |
| topLeft: Radius.circular(size.width * 0.009), | |
| topRight: Radius.circular(size.width * 0.009), | |
| ), | |
| backgroundPaint, | |
| ); | |
| // Calculate the width of each step | |
| double stepWidth = size.width / (totalSteps - 1); // Corrected to (totalSteps - 1) | |
| // Filled progress bar: Limit the width to the number of filled rounds | |
| Paint filledPaint = Paint()..style = PaintingStyle.fill; | |
| filledPaint.color = const Color(0xff2E2E54); | |
| canvas.drawRRect( | |
| RRect.fromRectAndCorners( | |
| Rect.fromLTWH(0, size.height * 0.25, stepWidth * (filledRounds - 1), // Start from first step | |
| size.height * 0.5), | |
| bottomRight: Radius.circular(size.width * 0.009), | |
| bottomLeft: Radius.circular(size.width * 0.009), | |
| topLeft: Radius.circular(size.width * 0.009), | |
| topRight: Radius.circular(size.width * 0.009), | |
| ), | |
| filledPaint, | |
| ); | |
| // Circle positions dynamically based on totalSteps | |
| List<double> circleOffsets = []; | |
| for (int i = 0; i < totalSteps; i++) { | |
| circleOffsets.add(stepWidth * i); // Corrected to start from the very beginning | |
| } | |
| for (int i = 0; i < totalSteps; i++) { | |
| bool isFilled = i < filledRounds; | |
| Paint borderPaint = Paint() | |
| ..color = isFilled ? Colors.white : const Color(0xff2E2E54) | |
| ..style = PaintingStyle.stroke | |
| ..strokeWidth = size.width * 0.003; | |
| Paint fillPaint = Paint()..style = PaintingStyle.fill; | |
| fillPaint.color = | |
| isFilled ? const Color(0xff2E2E54) : const Color(0xffE9E5EF); | |
| // Draw circle with border | |
| canvas.drawCircle( | |
| Offset(circleOffsets[i], size.height * 0.5), | |
| size.width * 0.0175, | |
| fillPaint, | |
| ); | |
| canvas.drawCircle( | |
| Offset(circleOffsets[i], size.height * 0.5), | |
| size.width * 0.0175, | |
| borderPaint, | |
| ); | |
| // Draw tick mark for filled circles | |
| if (isFilled) { | |
| Path tickPath = Path(); | |
| double tickStartX = circleOffsets[i] - size.width * 0.006; | |
| double tickStartY = size.height * 0.52; | |
| double tickMidX = circleOffsets[i] - size.width * 0.002; | |
| double tickMidY = size.height * 0.58; | |
| double tickEndX = circleOffsets[i] + size.width * 0.006; | |
| double tickEndY = size.height * 0.42; | |
| tickPath.moveTo(tickStartX, tickStartY); | |
| tickPath.lineTo(tickMidX, tickMidY); | |
| tickPath.lineTo(tickEndX, tickEndY); | |
| Paint tickPaint = Paint() | |
| ..color = Colors.white | |
| ..style = PaintingStyle.stroke | |
| ..strokeWidth = size.width * 0.003 | |
| ..strokeCap = StrokeCap.round | |
| ..strokeJoin = StrokeJoin.round; | |
| canvas.drawPath(tickPath, tickPaint); | |
| } | |
| } | |
| } | |
| @override | |
| bool shouldRepaint(covariant CustomPainter oldDelegate) { | |
| return true; | |
| } | |
| } |
Author
tejaswini-dev-techie
commented
Feb 13, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment