Unverified Commit d01d8aee authored by Alex Li's avatar Alex Li Committed by GitHub

Add `strokeAlign` to `CircularProgressIndicator` and `RefreshProgressIndicator` (#125945)

parent a3257ca5
......@@ -421,6 +421,7 @@ class _CircularProgressIndicatorPainter extends CustomPainter {
required this.offsetValue,
required this.rotationValue,
required this.strokeWidth,
required this.strokeAlign,
this.strokeCap,
}) : arcStart = value != null
? _startAngle
......@@ -437,6 +438,7 @@ class _CircularProgressIndicatorPainter extends CustomPainter {
final double offsetValue;
final double rotationValue;
final double strokeWidth;
final double strokeAlign;
final double arcStart;
final double arcSweep;
final StrokeCap? strokeCap;
......@@ -454,12 +456,27 @@ class _CircularProgressIndicatorPainter extends CustomPainter {
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke;
// Use the negative operator as intended to keep the exposed constant value
// as users are already familiar with.
final double strokeOffset = strokeWidth / 2 * -strokeAlign;
final Offset arcBaseOffset = Offset(strokeOffset, strokeOffset);
final Size arcActualSize = Size(
size.width - strokeOffset * 2,
size.height - strokeOffset * 2,
);
if (backgroundColor != null) {
final Paint backgroundPaint = Paint()
..color = backgroundColor!
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke;
canvas.drawArc(Offset.zero & size, 0, _sweep, false, backgroundPaint);
canvas.drawArc(
arcBaseOffset & arcActualSize,
0,
_sweep,
false,
backgroundPaint,
);
}
if (value == null && strokeCap == null) {
......@@ -470,7 +487,13 @@ class _CircularProgressIndicatorPainter extends CustomPainter {
paint.strokeCap = strokeCap ?? StrokeCap.butt;
}
canvas.drawArc(Offset.zero & size, arcStart, arcSweep, false, paint);
canvas.drawArc(
arcBaseOffset & arcActualSize,
arcStart,
arcSweep,
false,
paint,
);
}
@override
......@@ -483,6 +506,7 @@ class _CircularProgressIndicatorPainter extends CustomPainter {
|| oldPainter.offsetValue != offsetValue
|| oldPainter.rotationValue != rotationValue
|| oldPainter.strokeWidth != strokeWidth
|| oldPainter.strokeAlign != strokeAlign
|| oldPainter.strokeCap != strokeCap;
}
}
......@@ -538,6 +562,7 @@ class CircularProgressIndicator extends ProgressIndicator {
super.color,
super.valueColor,
this.strokeWidth = 4.0,
this.strokeAlign = strokeAlignCenter,
super.semanticsLabel,
super.semanticsValue,
this.strokeCap,
......@@ -560,6 +585,7 @@ class CircularProgressIndicator extends ProgressIndicator {
super.semanticsLabel,
super.semanticsValue,
this.strokeCap,
this.strokeAlign = strokeAlignCenter,
}) : _indicatorType = _ActivityIndicatorType.adaptive;
final _ActivityIndicatorType _indicatorType;
......@@ -577,6 +603,15 @@ class CircularProgressIndicator extends ProgressIndicator {
/// The width of the line used to draw the circle.
final double strokeWidth;
/// The relative position of the stroke on a [CircularProgressIndicator].
///
/// Values typically range from -1.0 ([strokeAlignInside], inside stroke)
/// to 1.0 ([strokeAlignOutside], outside stroke),
/// without any bound constraints (e.g., a value of -2.0 is not typical, but allowed).
/// A value of 0 ([strokeAlignCenter], default) will center the border
/// on the edge of the widget.
final double strokeAlign;
/// The progress indicator's line ending.
///
/// This determines the shape of the stroke ends of the progress indicator.
......@@ -598,6 +633,25 @@ class CircularProgressIndicator extends ProgressIndicator {
/// degrees and end at 275 degrees.
final StrokeCap? strokeCap;
/// The indicator stroke is drawn fully inside of the indicator path.
///
/// This is a constant for use with [strokeAlign].
static const double strokeAlignInside = -1.0;
/// The indicator stroke is drawn on the center of the indicator path,
/// with half of the [strokeWidth] on the inside, and the other half
/// on the outside of the path.
///
/// This is a constant for use with [strokeAlign].
///
/// This is the default value for [strokeAlign].
static const double strokeAlignCenter = 0.0;
/// The indicator stroke is drawn on the outside of the indicator path.
///
/// This is a constant for use with [strokeAlign].
static const double strokeAlignOutside = 1.0;
@override
State<CircularProgressIndicator> createState() => _CircularProgressIndicatorState();
}
......@@ -677,6 +731,7 @@ class _CircularProgressIndicatorState extends State<CircularProgressIndicator> w
offsetValue: offsetValue,
rotationValue: rotationValue,
strokeWidth: widget.strokeWidth,
strokeAlign: widget.strokeAlign,
strokeCap: widget.strokeCap,
),
),
......@@ -735,6 +790,7 @@ class _RefreshProgressIndicatorPainter extends _CircularProgressIndicatorPainter
required super.offsetValue,
required super.rotationValue,
required super.strokeWidth,
required super.strokeAlign,
required this.arrowheadScale,
required super.strokeCap,
});
......@@ -805,6 +861,7 @@ class RefreshProgressIndicator extends CircularProgressIndicator {
super.color,
super.valueColor,
super.strokeWidth = defaultStrokeWidth, // Different default than CircularProgressIndicator.
super.strokeAlign,
super.semanticsLabel,
super.semanticsValue,
super.strokeCap,
......@@ -936,6 +993,7 @@ class _RefreshProgressIndicatorState extends _CircularProgressIndicatorState {
offsetValue: offsetValue,
rotationValue: rotationValue,
strokeWidth: widget.strokeWidth,
strokeAlign: widget.strokeAlign,
arrowheadScale: arrowheadScale,
strokeCap: widget.strokeCap,
),
......
......@@ -443,6 +443,47 @@ void main() {
expect(find.byType(CircularProgressIndicator), paints..arc(strokeWidth: 16.0));
});
testWidgets('CircularProgressIndicator strokeAlign', (WidgetTester tester) async {
await tester.pumpWidget(
Theme(
data: theme,
child: const CircularProgressIndicator(),
),
);
expect(find.byType(CircularProgressIndicator), paints..arc(rect: Offset.zero & const Size(800.0, 600.0)));
await tester.pumpWidget(
Theme(
data: theme,
child: const CircularProgressIndicator(
strokeAlign: CircularProgressIndicator.strokeAlignInside,
),
),
);
expect(find.byType(CircularProgressIndicator), paints..arc(rect: const Offset(2.0, 2.0) & const Size(796.0, 596.0)));
await tester.pumpWidget(
Theme(
data: theme,
child: const CircularProgressIndicator(
strokeAlign: CircularProgressIndicator.strokeAlignOutside,
),
),
);
expect(find.byType(CircularProgressIndicator), paints..arc(rect: const Offset(-2.0, -2.0) & const Size(804.0, 604.0)));
// Unbounded alignment.
await tester.pumpWidget(
Theme(
data: theme,
child: const CircularProgressIndicator(
strokeAlign: 2.0,
),
),
);
expect(find.byType(CircularProgressIndicator), paints..arc(rect: const Offset(-4.0, -4.0) & const Size(808.0, 608.0)));
});
testWidgets('CircularProgressIndicator with strokeCap', (WidgetTester tester) async {
await tester.pumpWidget(const CircularProgressIndicator());
expect(find.byType(CircularProgressIndicator),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment