Skip to content

Instantly share code, notes, and snippets.

@sma
Created September 15, 2024 09:36
Show Gist options
  • Save sma/871379f8a57ce5ddacc945c7624802d3 to your computer and use it in GitHub Desktop.
Save sma/871379f8a57ce5ddacc945c7624802d3 to your computer and use it in GitHub Desktop.
A triangle shaped progress indicator
import 'dart:math';
import 'package:flutter/material.dart';
class TriangleProgress extends StatelessWidget {
final double value;
const TriangleProgress({super.key, required this.value});
@override
Widget build(BuildContext context) {
final color = Theme.of(context).colorScheme.primary;
final value = this.value.clamp(0, 1) as double;
return AspectRatio(
aspectRatio: 2 / sqrt(3),
child: CustomPaint(
painter: _TrianglePainter(
progress: value,
progressColor: color,
color: color.withOpacity(.4),
),
child: Align(
alignment: Alignment(0, .5),
child: Text(
'${(value * 100).round()}%',
style: Theme.of(context).textTheme.titleMedium,
),
),
),
);
}
}
class _TrianglePainter extends CustomPainter {
final double progress;
final Color progressColor;
final Color color;
_TrianglePainter({
required this.progress,
required this.progressColor,
required this.color,
});
@override
void paint(Canvas canvas, Size size) {
const kWidth = 4.0;
final double height = size.height - kWidth;
final double width = size.width - kWidth;
final Paint paint = Paint()
..color = color
..style = PaintingStyle.stroke
..strokeJoin = StrokeJoin.round
..strokeCap = StrokeCap.round
..strokeWidth = kWidth;
final Path path = Path()
..moveTo(kWidth / 2, height)
..lineTo(width / 2, kWidth / 2)
..lineTo(width, height)
..close();
canvas.drawPath(path, paint);
final metrics = path.computeMetrics().single;
final length = metrics.length * progress;
canvas.drawPath(
metrics.extractPath(0, length),
paint..color = progressColor,
);
}
@override
bool shouldRepaint(_TrianglePainter oldDelegate) =>
oldDelegate.progress != progress;
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: SizedBox(width: 80, child: TriangleProgress(value: .59)),
),
),
);
}
}
void main() {
runApp(const MyApp());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment