✨ Add strokeAlign
to CircularProgressIndicator
and RefreshProgressIndicator
(#125945)
This commit is contained in:
parent
a3257ca533
commit
d01d8aeed0
@ -421,6 +421,7 @@ class _CircularProgressIndicatorPainter extends CustomPainter {
|
|||||||
required this.offsetValue,
|
required this.offsetValue,
|
||||||
required this.rotationValue,
|
required this.rotationValue,
|
||||||
required this.strokeWidth,
|
required this.strokeWidth,
|
||||||
|
required this.strokeAlign,
|
||||||
this.strokeCap,
|
this.strokeCap,
|
||||||
}) : arcStart = value != null
|
}) : arcStart = value != null
|
||||||
? _startAngle
|
? _startAngle
|
||||||
@ -437,6 +438,7 @@ class _CircularProgressIndicatorPainter extends CustomPainter {
|
|||||||
final double offsetValue;
|
final double offsetValue;
|
||||||
final double rotationValue;
|
final double rotationValue;
|
||||||
final double strokeWidth;
|
final double strokeWidth;
|
||||||
|
final double strokeAlign;
|
||||||
final double arcStart;
|
final double arcStart;
|
||||||
final double arcSweep;
|
final double arcSweep;
|
||||||
final StrokeCap? strokeCap;
|
final StrokeCap? strokeCap;
|
||||||
@ -454,12 +456,27 @@ class _CircularProgressIndicatorPainter extends CustomPainter {
|
|||||||
..strokeWidth = strokeWidth
|
..strokeWidth = strokeWidth
|
||||||
..style = PaintingStyle.stroke;
|
..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) {
|
if (backgroundColor != null) {
|
||||||
final Paint backgroundPaint = Paint()
|
final Paint backgroundPaint = Paint()
|
||||||
..color = backgroundColor!
|
..color = backgroundColor!
|
||||||
..strokeWidth = strokeWidth
|
..strokeWidth = strokeWidth
|
||||||
..style = PaintingStyle.stroke;
|
..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) {
|
if (value == null && strokeCap == null) {
|
||||||
@ -470,7 +487,13 @@ class _CircularProgressIndicatorPainter extends CustomPainter {
|
|||||||
paint.strokeCap = strokeCap ?? StrokeCap.butt;
|
paint.strokeCap = strokeCap ?? StrokeCap.butt;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.drawArc(Offset.zero & size, arcStart, arcSweep, false, paint);
|
canvas.drawArc(
|
||||||
|
arcBaseOffset & arcActualSize,
|
||||||
|
arcStart,
|
||||||
|
arcSweep,
|
||||||
|
false,
|
||||||
|
paint,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -483,6 +506,7 @@ class _CircularProgressIndicatorPainter extends CustomPainter {
|
|||||||
|| oldPainter.offsetValue != offsetValue
|
|| oldPainter.offsetValue != offsetValue
|
||||||
|| oldPainter.rotationValue != rotationValue
|
|| oldPainter.rotationValue != rotationValue
|
||||||
|| oldPainter.strokeWidth != strokeWidth
|
|| oldPainter.strokeWidth != strokeWidth
|
||||||
|
|| oldPainter.strokeAlign != strokeAlign
|
||||||
|| oldPainter.strokeCap != strokeCap;
|
|| oldPainter.strokeCap != strokeCap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -538,6 +562,7 @@ class CircularProgressIndicator extends ProgressIndicator {
|
|||||||
super.color,
|
super.color,
|
||||||
super.valueColor,
|
super.valueColor,
|
||||||
this.strokeWidth = 4.0,
|
this.strokeWidth = 4.0,
|
||||||
|
this.strokeAlign = strokeAlignCenter,
|
||||||
super.semanticsLabel,
|
super.semanticsLabel,
|
||||||
super.semanticsValue,
|
super.semanticsValue,
|
||||||
this.strokeCap,
|
this.strokeCap,
|
||||||
@ -560,6 +585,7 @@ class CircularProgressIndicator extends ProgressIndicator {
|
|||||||
super.semanticsLabel,
|
super.semanticsLabel,
|
||||||
super.semanticsValue,
|
super.semanticsValue,
|
||||||
this.strokeCap,
|
this.strokeCap,
|
||||||
|
this.strokeAlign = strokeAlignCenter,
|
||||||
}) : _indicatorType = _ActivityIndicatorType.adaptive;
|
}) : _indicatorType = _ActivityIndicatorType.adaptive;
|
||||||
|
|
||||||
final _ActivityIndicatorType _indicatorType;
|
final _ActivityIndicatorType _indicatorType;
|
||||||
@ -577,6 +603,15 @@ class CircularProgressIndicator extends ProgressIndicator {
|
|||||||
/// The width of the line used to draw the circle.
|
/// The width of the line used to draw the circle.
|
||||||
final double strokeWidth;
|
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.
|
/// The progress indicator's line ending.
|
||||||
///
|
///
|
||||||
/// This determines the shape of the stroke ends of the progress indicator.
|
/// 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.
|
/// degrees and end at 275 degrees.
|
||||||
final StrokeCap? strokeCap;
|
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
|
@override
|
||||||
State<CircularProgressIndicator> createState() => _CircularProgressIndicatorState();
|
State<CircularProgressIndicator> createState() => _CircularProgressIndicatorState();
|
||||||
}
|
}
|
||||||
@ -677,6 +731,7 @@ class _CircularProgressIndicatorState extends State<CircularProgressIndicator> w
|
|||||||
offsetValue: offsetValue,
|
offsetValue: offsetValue,
|
||||||
rotationValue: rotationValue,
|
rotationValue: rotationValue,
|
||||||
strokeWidth: widget.strokeWidth,
|
strokeWidth: widget.strokeWidth,
|
||||||
|
strokeAlign: widget.strokeAlign,
|
||||||
strokeCap: widget.strokeCap,
|
strokeCap: widget.strokeCap,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -735,6 +790,7 @@ class _RefreshProgressIndicatorPainter extends _CircularProgressIndicatorPainter
|
|||||||
required super.offsetValue,
|
required super.offsetValue,
|
||||||
required super.rotationValue,
|
required super.rotationValue,
|
||||||
required super.strokeWidth,
|
required super.strokeWidth,
|
||||||
|
required super.strokeAlign,
|
||||||
required this.arrowheadScale,
|
required this.arrowheadScale,
|
||||||
required super.strokeCap,
|
required super.strokeCap,
|
||||||
});
|
});
|
||||||
@ -805,6 +861,7 @@ class RefreshProgressIndicator extends CircularProgressIndicator {
|
|||||||
super.color,
|
super.color,
|
||||||
super.valueColor,
|
super.valueColor,
|
||||||
super.strokeWidth = defaultStrokeWidth, // Different default than CircularProgressIndicator.
|
super.strokeWidth = defaultStrokeWidth, // Different default than CircularProgressIndicator.
|
||||||
|
super.strokeAlign,
|
||||||
super.semanticsLabel,
|
super.semanticsLabel,
|
||||||
super.semanticsValue,
|
super.semanticsValue,
|
||||||
super.strokeCap,
|
super.strokeCap,
|
||||||
@ -936,6 +993,7 @@ class _RefreshProgressIndicatorState extends _CircularProgressIndicatorState {
|
|||||||
offsetValue: offsetValue,
|
offsetValue: offsetValue,
|
||||||
rotationValue: rotationValue,
|
rotationValue: rotationValue,
|
||||||
strokeWidth: widget.strokeWidth,
|
strokeWidth: widget.strokeWidth,
|
||||||
|
strokeAlign: widget.strokeAlign,
|
||||||
arrowheadScale: arrowheadScale,
|
arrowheadScale: arrowheadScale,
|
||||||
strokeCap: widget.strokeCap,
|
strokeCap: widget.strokeCap,
|
||||||
),
|
),
|
||||||
|
@ -443,6 +443,47 @@ void main() {
|
|||||||
expect(find.byType(CircularProgressIndicator), paints..arc(strokeWidth: 16.0));
|
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 {
|
testWidgets('CircularProgressIndicator with strokeCap', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(const CircularProgressIndicator());
|
await tester.pumpWidget(const CircularProgressIndicator());
|
||||||
expect(find.byType(CircularProgressIndicator),
|
expect(find.byType(CircularProgressIndicator),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user