-
Notifications
You must be signed in to change notification settings - Fork 666
Expand file tree
/
Copy pathgradient_circular_progress_indicator.dart
More file actions
174 lines (154 loc) · 5.29 KB
/
gradient_circular_progress_indicator.dart
File metadata and controls
174 lines (154 loc) · 5.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import 'dart:math';
import 'package:flutter/material.dart';
/// A circular progress indicator with gradient effect.
class GradientCircularProgressIndicator extends StatelessWidget {
const GradientCircularProgressIndicator({
Key? key,
required this.radius,
this.stokeWidth = 2.0,
this.colors,
this.stops,
this.strokeCapRound = false,
this.backgroundColor = const Color(0xFFEEEEEE),
this.totalAngle = 2 * pi,
this.fullColor,
this.value,
}) : super(key: key);
/// The width of the line used to draw the circle.
final double stokeWidth;
/// The radius of the [GradientCircularProgressIndicator]
final double radius;
/// The kind of finish to place on the end of arc drawn .
/// if `true`, [StrokeCap.round] will be set to `Paint.strokeCap`.
final bool strokeCapRound;
/// The value of this progress indicator with 0.0 corresponding
/// to no progress having been made and 1.0 corresponding to all the progress
/// having been made.
final double? value;
/// The progress color when value is 1.
final Color? fullColor;
/// The progress indicator's background color. The current theme's
/// `Color(0xFFEEEEEE)` by default.
final Color backgroundColor;
/// The total angle of the progress. Defaults to 2*pi (entire circle)
final double totalAngle;
/// The colors the gradient should obtain at each of the stops.
///
/// If [stops] is non-null, this list must have the same length as [stops].
///
/// This list must have at least two colors in it (otherwise, it's not a
/// gradient!).
final List<Color>? colors;
/// A list of values from 0.0 to 1.0 that denote fractions along the gradient.
///
/// If non-null, this list must have the same length as [colors].
///
/// If the first value is not 0.0, then a stop with position 0.0 and a color
/// equal to the first color in [colors] is implied.
///
/// If the last value is not 1.0, then a stop with position 1.0 and a color
/// equal to the last color in [colors] is implied.
///
/// The values in the [stops] list must be in ascending order. If a value in
/// the [stops] list is less than an earlier value in the list, then its value
/// is assumed to equal the previous value.
///
/// If stops is null, then a set of uniformly distributed stops is implied,
/// with the first stop at 0.0 and the last stop at 1.0.
final List<double>? stops;
@override
Widget build(BuildContext context) {
double _offset = .0;
if (strokeCapRound && totalAngle != 2 * pi) {
_offset = asin(stokeWidth / (radius * 2 - stokeWidth));
}
var _colors = colors;
if (_colors == null) {
Color color = Theme.of(context).colorScheme.secondary;
_colors = [color, color];
}
return Transform.rotate(
angle: -pi / 2.0 - _offset,
child: CustomPaint(
size: Size.fromRadius(radius),
painter: _GradientCircularProgressPainter(
stokeWidth: stokeWidth,
strokeCapRound: strokeCapRound,
backgroundColor: backgroundColor,
value: value,
fullColor: fullColor,
total: totalAngle,
radius: radius,
colors: _colors,
),
),
);
}
}
class _GradientCircularProgressPainter extends CustomPainter {
const _GradientCircularProgressPainter({
this.stokeWidth = 10.0,
this.strokeCapRound = false,
this.backgroundColor = const Color(0xFFEEEEEE),
this.radius,
this.total = 2 * pi,
required this.colors,
this.value,
this.fullColor,
});
final double stokeWidth;
final bool strokeCapRound;
final double? value;
final Color backgroundColor;
final List<Color> colors;
final double total;
final double? radius;
final Color? fullColor;
@override
void paint(Canvas canvas, Size size) {
if (radius != null) {
size = Size.fromRadius(radius!);
}
double _offset = stokeWidth / 2.0;
double _value = (value ?? .0);
_value = _value.clamp(.0, 1.0) * total;
double _start = .0;
if (strokeCapRound) {
_start = asin(stokeWidth / (size.width - stokeWidth));
}
Rect rect = Offset(_offset, _offset) &
Size(size.width - stokeWidth, size.height - stokeWidth);
var paint = Paint()
..strokeCap = strokeCapRound ? StrokeCap.round : StrokeCap.butt
..style = PaintingStyle.stroke
..isAntiAlias = true
..strokeWidth = stokeWidth;
// draw background arc
if (backgroundColor != Colors.transparent) {
paint.color = backgroundColor;
canvas.drawArc(rect, _start, total, false, paint);
}
if (value == 1 && fullColor != null) {
paint.color = fullColor!;
canvas.drawArc(rect, _start, _value, false, paint);
} else if (_value > 0) {
// draw foreground arc and apply gradient
paint.shader = SweepGradient(
startAngle: 0.0,
endAngle: _value,
colors: colors,
).createShader(rect);
canvas.drawArc(rect, _start, _value, false, paint);
}
}
@override
bool shouldRepaint(_GradientCircularProgressPainter old) {
return old.stokeWidth != stokeWidth ||
old.strokeCapRound != strokeCapRound ||
old.backgroundColor != backgroundColor ||
old.radius != radius ||
old.value != value ||
old.fullColor != fullColor ||
old.colors.toString() != colors.toString();
}
}