mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Update Material 3 LinearProgressIndicator
for new visual style (#154817)
Related to [Update both `ProgressIndicator` for Material 3 redesign](https://github.com/flutter/flutter/issues/141340) ### Code sample <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { bool isRTL = false; @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( body: Directionality( textDirection: isRTL ? TextDirection.rtl : TextDirection.ltr, child: Center( child: Column( spacing: 2.0, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const Text('Default LinearProgressIndicator'), const Padding( padding: EdgeInsets.all(16.0), child: LinearProgressIndicator( value: 0.45, ), ), const Text('Default indefinite LinearProgressIndicator'), const Padding( padding: EdgeInsets.all(16.0), child: LinearProgressIndicator(), ), const Text('Updated height and border radius'), Padding( padding: const EdgeInsets.all(16.0), child: LinearProgressIndicator( value: 0.25, minHeight: 16.0, borderRadius: BorderRadius.circular(16.0), ), ), const Text('Updated stop indicator color and radius'), Padding( padding: const EdgeInsets.all(16.0), child: LinearProgressIndicator( value: 0.74, minHeight: 16.0, borderRadius: BorderRadius.circular(16.0), stopIndicatorColor: Theme.of(context).colorScheme.error, stopIndicatorRadius: 32.0, ), ), const Text('Track gap and stop indicator radius set to 0'), Padding( padding: const EdgeInsets.all(16.0), child: LinearProgressIndicator( value: 0.50, minHeight: 16.0, borderRadius: BorderRadius.circular(16.0), trackGap: 0, stopIndicatorRadius: 0, ), ), ], ), ), ), floatingActionButton: FloatingActionButton.extended( onPressed: () { setState(() { isRTL = !isRTL; }); }, label: const Text('Toggle Direction'), ), ), ); } } ``` </details> ### Preview <img width="824" alt="Screenshot 2024-09-09 at 13 53 10" src="https://github.com/user-attachments/assets/d12e56a5-f196-4011-8266-c7ab96be96b2">
This commit is contained in:
parent
cf4a4b8162
commit
b8dcb0c3c5
@ -585,7 +585,10 @@ md.comp.primary-navigation-tab.inactive.pressed.state-layer.opacity,
|
||||
md.comp.primary-navigation-tab.with-label-text.active.label-text.color,
|
||||
md.comp.primary-navigation-tab.with-label-text.inactive.label-text.color,
|
||||
md.comp.primary-navigation-tab.with-label-text.label-text.text-style,
|
||||
md.comp.progress-indicator.active-indicator-track-space,
|
||||
md.comp.progress-indicator.active-indicator.color,
|
||||
md.comp.progress-indicator.stop-indicator.color,
|
||||
md.comp.progress-indicator.stop-indicator.size,
|
||||
md.comp.progress-indicator.track.color,
|
||||
md.comp.progress-indicator.track.thickness,
|
||||
md.comp.radio-button.disabled.selected.icon.color,
|
||||
|
|
@ -38,6 +38,18 @@ class _Linear${blockName}DefaultsM3 extends ProgressIndicatorThemeData {
|
||||
|
||||
@override
|
||||
double get linearMinHeight => ${getToken('md.comp.progress-indicator.track.thickness')};
|
||||
|
||||
@override
|
||||
BorderRadius get borderRadius => BorderRadius.circular(${getToken('md.comp.progress-indicator.track.thickness')} / 2);
|
||||
|
||||
@override
|
||||
Color get stopIndicatorColor => ${componentColor('md.comp.progress-indicator.stop-indicator')};
|
||||
|
||||
@override
|
||||
double? get stopIndicatorRadius => ${getToken('md.comp.progress-indicator.stop-indicator.size')} / 2;
|
||||
|
||||
@override
|
||||
double? get trackGap => ${getToken('md.comp.progress-indicator.active-indicator-track-space')};
|
||||
}
|
||||
''';
|
||||
}
|
||||
|
@ -6,10 +6,10 @@ import 'package:flutter/material.dart';
|
||||
|
||||
/// Flutter code sample for [LinearProgressIndicator].
|
||||
|
||||
void main() => runApp(const ProgressIndicatorApp());
|
||||
void main() => runApp(const ProgressIndicatorExampleApp());
|
||||
|
||||
class ProgressIndicatorApp extends StatelessWidget {
|
||||
const ProgressIndicatorApp({super.key});
|
||||
class ProgressIndicatorExampleApp extends StatelessWidget {
|
||||
const ProgressIndicatorExampleApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -23,24 +23,26 @@ class ProgressIndicatorExample extends StatefulWidget {
|
||||
const ProgressIndicatorExample({super.key});
|
||||
|
||||
@override
|
||||
State<ProgressIndicatorExample> createState() => _ProgressIndicatorExampleState();
|
||||
State<ProgressIndicatorExample> createState() =>
|
||||
_ProgressIndicatorExampleState();
|
||||
}
|
||||
|
||||
class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample> with TickerProviderStateMixin {
|
||||
class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample>
|
||||
with TickerProviderStateMixin {
|
||||
late AnimationController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
controller = AnimationController(
|
||||
/// [AnimationController]s can be created with `vsync: this` because of
|
||||
/// [TickerProviderStateMixin].
|
||||
vsync: this,
|
||||
duration: const Duration(seconds: 5),
|
||||
)..addListener(() {
|
||||
setState(() {});
|
||||
});
|
||||
controller.repeat(reverse: true);
|
||||
super.initState();
|
||||
setState(() {});
|
||||
})
|
||||
..repeat(reverse: true);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -55,16 +57,13 @@ class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample> wit
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
spacing: 16.0,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
const Text(
|
||||
'Linear progress indicator with a fixed color',
|
||||
style: TextStyle(fontSize: 20),
|
||||
),
|
||||
LinearProgressIndicator(
|
||||
value: controller.value,
|
||||
semanticsLabel: 'Linear progress indicator',
|
||||
),
|
||||
const Text('Determinate LinearProgressIndicator'),
|
||||
LinearProgressIndicator(value: controller.value),
|
||||
const Text('Indeterminate LinearProgressIndicator'),
|
||||
const LinearProgressIndicator(),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -6,16 +6,15 @@ import 'package:flutter/material.dart';
|
||||
|
||||
/// Flutter code sample for [LinearProgressIndicator].
|
||||
|
||||
void main() => runApp(const ProgressIndicatorApp());
|
||||
void main() => runApp(const ProgressIndicatorExampleApp());
|
||||
|
||||
class ProgressIndicatorApp extends StatelessWidget {
|
||||
const ProgressIndicatorApp({super.key});
|
||||
class ProgressIndicatorExampleApp extends StatelessWidget {
|
||||
const ProgressIndicatorExampleApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(useMaterial3: true, colorSchemeSeed: const Color(0xff6750a4)),
|
||||
home: const ProgressIndicatorExample(),
|
||||
return const MaterialApp(
|
||||
home: ProgressIndicatorExample(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -24,25 +23,27 @@ class ProgressIndicatorExample extends StatefulWidget {
|
||||
const ProgressIndicatorExample({super.key});
|
||||
|
||||
@override
|
||||
State<ProgressIndicatorExample> createState() => _ProgressIndicatorExampleState();
|
||||
State<ProgressIndicatorExample> createState() =>
|
||||
_ProgressIndicatorExampleState();
|
||||
}
|
||||
|
||||
class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample> with TickerProviderStateMixin {
|
||||
class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample>
|
||||
with TickerProviderStateMixin {
|
||||
late AnimationController controller;
|
||||
bool determinate = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
controller = AnimationController(
|
||||
/// [AnimationController]s can be created with `vsync: this` because of
|
||||
/// [TickerProviderStateMixin].
|
||||
vsync: this,
|
||||
duration: const Duration(seconds: 2),
|
||||
)..addListener(() {
|
||||
setState(() {});
|
||||
});
|
||||
controller.repeat();
|
||||
super.initState();
|
||||
setState(() {});
|
||||
})
|
||||
..repeat(reverse: true);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -65,7 +66,7 @@ class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample> wit
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
LinearProgressIndicator(
|
||||
value: controller.value,
|
||||
value: determinate ? controller.value : null,
|
||||
semanticsLabel: 'Linear progress indicator',
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
@ -73,7 +74,7 @@ class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample> wit
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
'determinate Mode',
|
||||
'${determinate ? 'Determinate' : 'Indeterminate'} Mode',
|
||||
style: Theme.of(context).textTheme.titleSmall,
|
||||
),
|
||||
),
|
||||
|
@ -2,23 +2,39 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_api_samples/material/progress_indicator/linear_progress_indicator.0.dart'
|
||||
as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Finds LinearProgressIndicator', (WidgetTester tester) async {
|
||||
testWidgets('Determinate and Indeterminate LinearProgressIndicators',
|
||||
(WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.ProgressIndicatorApp(),
|
||||
const example.ProgressIndicatorExampleApp(),
|
||||
);
|
||||
|
||||
expect(
|
||||
find.bySemanticsLabel('Linear progress indicator'),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.text('Determinate LinearProgressIndicator'), findsOneWidget);
|
||||
expect(find.text('Indeterminate LinearProgressIndicator'), findsOneWidget);
|
||||
expect(find.byType(LinearProgressIndicator), findsNWidgets(2));
|
||||
|
||||
// Test if LinearProgressIndicator is animating.
|
||||
// Test determinate LinearProgressIndicator.
|
||||
LinearProgressIndicator determinateIndicator = tester.firstWidget(
|
||||
find.byType(LinearProgressIndicator).first,
|
||||
);
|
||||
expect(determinateIndicator.value, equals(0.0));
|
||||
|
||||
// Advance the animation by 2 seconds.
|
||||
await tester.pump(const Duration(seconds: 2));
|
||||
expect(tester.hasRunningAnimations, isTrue);
|
||||
determinateIndicator = tester.firstWidget(
|
||||
find.byType(LinearProgressIndicator).first,
|
||||
);
|
||||
expect(determinateIndicator.value, equals(0.4));
|
||||
|
||||
// Test indeterminate LinearProgressIndicator.
|
||||
final LinearProgressIndicator indeterminateIndicator = tester.firstWidget(
|
||||
find.byType(LinearProgressIndicator).last,
|
||||
);
|
||||
expect(indeterminateIndicator.value, null);
|
||||
});
|
||||
}
|
||||
|
@ -8,9 +8,10 @@ import 'package:flutter_api_samples/material/progress_indicator/linear_progress_
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Finds LinearProgressIndicator', (WidgetTester tester) async {
|
||||
testWidgets('Can control LinearProgressIndicator value',
|
||||
(WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.ProgressIndicatorApp(),
|
||||
const example.ProgressIndicatorExampleApp(),
|
||||
);
|
||||
|
||||
expect(
|
||||
|
@ -145,20 +145,26 @@ abstract class ProgressIndicator extends StatefulWidget {
|
||||
|
||||
class _LinearProgressIndicatorPainter extends CustomPainter {
|
||||
const _LinearProgressIndicatorPainter({
|
||||
required this.backgroundColor,
|
||||
required this.trackColor,
|
||||
required this.valueColor,
|
||||
this.value,
|
||||
required this.animationValue,
|
||||
required this.textDirection,
|
||||
required this.indicatorBorderRadius,
|
||||
required this.stopIndicatorColor,
|
||||
required this.stopIndicatorRadius,
|
||||
required this.trackGap,
|
||||
});
|
||||
|
||||
final Color backgroundColor;
|
||||
final Color trackColor;
|
||||
final Color valueColor;
|
||||
final double? value;
|
||||
final double animationValue;
|
||||
final TextDirection textDirection;
|
||||
final BorderRadiusGeometry indicatorBorderRadius;
|
||||
final BorderRadiusGeometry? indicatorBorderRadius;
|
||||
final Color? stopIndicatorColor;
|
||||
final double? stopIndicatorRadius;
|
||||
final double? trackGap;
|
||||
|
||||
// The indeterminate progress animation displays two lines whose leading (head)
|
||||
// and trailing (tail) endpoints are defined by the following four curves.
|
||||
@ -185,33 +191,78 @@ class _LinearProgressIndicatorPainter extends CustomPainter {
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final Paint paint = Paint()
|
||||
..color = backgroundColor
|
||||
..style = PaintingStyle.fill;
|
||||
final double effectiveTrackGap = switch (value) {
|
||||
null || 1.0 => 0.0,
|
||||
_ => trackGap ?? 0.0,
|
||||
};
|
||||
|
||||
paint.color = valueColor;
|
||||
final Rect trackRect;
|
||||
if (value != null && effectiveTrackGap > 0) {
|
||||
trackRect = switch (textDirection) {
|
||||
TextDirection.ltr => Rect.fromLTRB(
|
||||
clampDouble(value!, 0.0, 1.0) * size.width + effectiveTrackGap,
|
||||
0,
|
||||
size.width,
|
||||
size.height,
|
||||
),
|
||||
TextDirection.rtl => Rect.fromLTRB(
|
||||
0,
|
||||
0,
|
||||
size.width - clampDouble(value!, 0.0, 1.0) * size.width - effectiveTrackGap,
|
||||
size.height,
|
||||
),
|
||||
};
|
||||
} else {
|
||||
trackRect = Offset.zero & size;
|
||||
}
|
||||
|
||||
void drawBar(double x, double width) {
|
||||
// Draw the track.
|
||||
final Paint trackPaint = Paint()..color = trackColor;
|
||||
if (indicatorBorderRadius != null) {
|
||||
final RRect trackRRect = indicatorBorderRadius!.resolve(textDirection).toRRect(trackRect);
|
||||
canvas.drawRRect(trackRRect, trackPaint);
|
||||
} else {
|
||||
canvas.drawRect(trackRect, trackPaint);
|
||||
}
|
||||
|
||||
void drawStopIndicator() {
|
||||
// Limit the stop indicator radius to the height of the indicator.
|
||||
final double radius = math.min(stopIndicatorRadius!, size.height / 2);
|
||||
final Paint indicatorPaint = Paint()..color = stopIndicatorColor!;
|
||||
final Offset position = switch (textDirection) {
|
||||
TextDirection.rtl => Offset(size.height / 2, size.height / 2),
|
||||
TextDirection.ltr => Offset(size.width - size.height / 2, size.height / 2),
|
||||
};
|
||||
canvas.drawCircle(position, radius, indicatorPaint);
|
||||
}
|
||||
|
||||
// Draw the stop indicator.
|
||||
if (value != null && stopIndicatorRadius != null && stopIndicatorRadius! > 0) {
|
||||
drawStopIndicator();
|
||||
}
|
||||
|
||||
void drawActiveIndicator(double x, double width) {
|
||||
if (width <= 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Paint activeIndicatorPaint = Paint()..color = valueColor;
|
||||
final double left = switch (textDirection) {
|
||||
TextDirection.rtl => size.width - width - x,
|
||||
TextDirection.ltr => x,
|
||||
};
|
||||
|
||||
final Rect rect = Offset(left, 0.0) & Size(width, size.height);
|
||||
if (indicatorBorderRadius != BorderRadius.zero) {
|
||||
final RRect rrect = indicatorBorderRadius.resolve(textDirection).toRRect(rect);
|
||||
canvas.drawRRect(rrect, paint);
|
||||
final Rect activeRect = Offset(left, 0.0) & Size(width, size.height);
|
||||
if (indicatorBorderRadius != null) {
|
||||
final RRect activeRRect = indicatorBorderRadius!.resolve(textDirection).toRRect(activeRect);
|
||||
canvas.drawRRect(activeRRect, activeIndicatorPaint);
|
||||
} else {
|
||||
canvas.drawRect(rect, paint);
|
||||
canvas.drawRect(activeRect, activeIndicatorPaint);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the active indicator.
|
||||
if (value != null) {
|
||||
drawBar(0.0, clampDouble(value!, 0.0, 1.0) * size.width);
|
||||
drawActiveIndicator(0.0, clampDouble(value!, 0.0, 1.0) * size.width);
|
||||
} else {
|
||||
final double x1 = size.width * line1Tail.transform(animationValue);
|
||||
final double width1 = size.width * line1Head.transform(animationValue) - x1;
|
||||
@ -219,19 +270,22 @@ class _LinearProgressIndicatorPainter extends CustomPainter {
|
||||
final double x2 = size.width * line2Tail.transform(animationValue);
|
||||
final double width2 = size.width * line2Head.transform(animationValue) - x2;
|
||||
|
||||
drawBar(x1, width1);
|
||||
drawBar(x2, width2);
|
||||
drawActiveIndicator(x1, width1);
|
||||
drawActiveIndicator(x2, width2);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_LinearProgressIndicatorPainter oldPainter) {
|
||||
return oldPainter.backgroundColor != backgroundColor
|
||||
return oldPainter.trackColor != trackColor
|
||||
|| oldPainter.valueColor != valueColor
|
||||
|| oldPainter.value != value
|
||||
|| oldPainter.animationValue != animationValue
|
||||
|| oldPainter.textDirection != textDirection
|
||||
|| oldPainter.indicatorBorderRadius != indicatorBorderRadius;
|
||||
|| oldPainter.indicatorBorderRadius != indicatorBorderRadius
|
||||
|| oldPainter.stopIndicatorColor != stopIndicatorColor
|
||||
|| oldPainter.stopIndicatorRadius != stopIndicatorRadius
|
||||
|| oldPainter.trackGap != trackGap;
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,7 +312,7 @@ class _LinearProgressIndicatorPainter extends CustomPainter {
|
||||
/// The indicator can be made taller by wrapping the widget with a [SizedBox].
|
||||
///
|
||||
/// {@tool dartpad}
|
||||
/// This example shows a [LinearProgressIndicator] with a changing value.
|
||||
/// This example showcases determinate and indeterminate [LinearProgressIndicator]s.
|
||||
///
|
||||
/// ** See code in examples/api/lib/material/progress_indicator/linear_progress_indicator.0.dart **
|
||||
/// {@end-tool}
|
||||
@ -290,7 +344,15 @@ class LinearProgressIndicator extends ProgressIndicator {
|
||||
this.minHeight,
|
||||
super.semanticsLabel,
|
||||
super.semanticsValue,
|
||||
this.borderRadius = BorderRadius.zero,
|
||||
this.borderRadius,
|
||||
this.stopIndicatorColor,
|
||||
this.stopIndicatorRadius,
|
||||
this.trackGap,
|
||||
@Deprecated(
|
||||
'Use ProgressIndicatorTheme to customize the ProgressIndicator appearance. '
|
||||
'This feature was deprecated after v3.26.0-0.1.pre.'
|
||||
)
|
||||
this.year2023 = true,
|
||||
}) : assert(minHeight == null || minHeight > 0);
|
||||
|
||||
/// {@template flutter.material.LinearProgressIndicator.trackColor}
|
||||
@ -315,9 +377,56 @@ class LinearProgressIndicator extends ProgressIndicator {
|
||||
|
||||
/// The border radius of both the indicator and the track.
|
||||
///
|
||||
/// By default it is [BorderRadius.zero], which produces a rectangular shape
|
||||
/// If null, then the [ProgressIndicatorThemeData.borderRadius] will be used.
|
||||
/// If that is also null, then defaults to radius of 2, which produces a
|
||||
/// rounded shape with a rounded indicator. If [ThemeData.useMaterial3] is false,
|
||||
/// then defaults to [BorderRadius.zero], which produces a rectangular shape
|
||||
/// with a rectangular indicator.
|
||||
final BorderRadiusGeometry borderRadius;
|
||||
final BorderRadiusGeometry? borderRadius;
|
||||
|
||||
/// The color of the stop indicator.
|
||||
///
|
||||
/// If [year2023] is false or [ThemeData.useMaterial3] is false, then no stop
|
||||
/// indicator will be drawn.
|
||||
///
|
||||
/// If null, then the [ProgressIndicatorThemeData.stopIndicatorColor] will be used.
|
||||
/// If that is null, then the [ColorScheme.primary] will be used.
|
||||
final Color? stopIndicatorColor;
|
||||
|
||||
/// The radius of the stop indicator.
|
||||
///
|
||||
/// If [year2023] is false or [ThemeData.useMaterial3] is false, then no stop
|
||||
/// indicator will be drawn.
|
||||
///
|
||||
/// Set [stopIndicatorRadius] to 0 to hide the stop indicator.
|
||||
///
|
||||
/// If null, then the [ProgressIndicatorThemeData.stopIndicatorRadius] will be used.
|
||||
/// If that is null, then defaults to 2.
|
||||
final double? stopIndicatorRadius;
|
||||
|
||||
/// The gap between the indicator and the track.
|
||||
///
|
||||
/// If [year2023] is false or [ThemeData.useMaterial3] is false, then no track
|
||||
/// gap will be drawn.
|
||||
///
|
||||
/// Set [trackGap] to 0 to hide the track gap.
|
||||
///
|
||||
/// If null, then the [ProgressIndicatorThemeData.trackGap] will be used.
|
||||
/// If that is null, then defaults to 4.
|
||||
final double? trackGap;
|
||||
|
||||
/// When true, the [LinearProgressIndicator] will use the 2023 Material 3
|
||||
/// Design appearance.
|
||||
///
|
||||
/// Defaults to true. If false, the [LinearProgressIndicator] will use the
|
||||
/// latest Material 3 Design appearance, which was introduced in December 2023.
|
||||
///
|
||||
/// If [ThemeData.useMaterial3] is false, then this property is ignored.
|
||||
@Deprecated(
|
||||
'Use ProgressIndicatorTheme to customize the ProgressIndicator appearance. '
|
||||
'This feature was deprecated after v3.27.0-0.1.pre.'
|
||||
)
|
||||
final bool year2023;
|
||||
|
||||
@override
|
||||
State<LinearProgressIndicator> createState() => _LinearProgressIndicatorState();
|
||||
@ -355,9 +464,12 @@ class _LinearProgressIndicatorState extends State<LinearProgressIndicator> with
|
||||
}
|
||||
|
||||
Widget _buildIndicator(BuildContext context, double animationValue, TextDirection textDirection) {
|
||||
final ProgressIndicatorThemeData defaults = Theme.of(context).useMaterial3
|
||||
? _LinearProgressIndicatorDefaultsM3(context)
|
||||
: _LinearProgressIndicatorDefaultsM2(context);
|
||||
final ProgressIndicatorThemeData defaults = switch (Theme.of(context).useMaterial3) {
|
||||
true => widget.year2023
|
||||
? _LinearProgressIndicatorDefaultsM3Year2023(context)
|
||||
: _LinearProgressIndicatorDefaultsM3(context),
|
||||
false => _LinearProgressIndicatorDefaultsM2(context),
|
||||
};
|
||||
|
||||
final ProgressIndicatorThemeData indicatorTheme = ProgressIndicatorTheme.of(context);
|
||||
final Color trackColor = widget.backgroundColor ??
|
||||
@ -366,33 +478,56 @@ class _LinearProgressIndicatorState extends State<LinearProgressIndicator> with
|
||||
final double minHeight = widget.minHeight ??
|
||||
indicatorTheme.linearMinHeight ??
|
||||
defaults.linearMinHeight!;
|
||||
final BorderRadiusGeometry? borderRadius = widget.borderRadius
|
||||
?? indicatorTheme.borderRadius
|
||||
?? defaults.borderRadius;
|
||||
final Color? stopIndicatorColor = !widget.year2023
|
||||
? widget.stopIndicatorColor ??
|
||||
indicatorTheme.stopIndicatorColor ??
|
||||
defaults.stopIndicatorColor
|
||||
: null;
|
||||
final double? stopIndicatorRadius = !widget.year2023
|
||||
? widget.stopIndicatorRadius ??
|
||||
indicatorTheme.stopIndicatorRadius ??
|
||||
defaults.stopIndicatorRadius
|
||||
: null;
|
||||
final double? trackGap = !widget.year2023
|
||||
? widget.trackGap ??
|
||||
indicatorTheme.trackGap ??
|
||||
defaults.trackGap
|
||||
: null;
|
||||
|
||||
Widget result = ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minWidth: double.infinity,
|
||||
minHeight: minHeight,
|
||||
),
|
||||
child: CustomPaint(
|
||||
painter: _LinearProgressIndicatorPainter(
|
||||
trackColor: trackColor,
|
||||
valueColor: widget._getValueColor(context, defaultColor: defaults.color),
|
||||
value: widget.value, // may be null
|
||||
animationValue: animationValue, // ignored if widget.value is not null
|
||||
textDirection: textDirection,
|
||||
indicatorBorderRadius: borderRadius,
|
||||
stopIndicatorColor: stopIndicatorColor,
|
||||
stopIndicatorRadius: stopIndicatorRadius,
|
||||
trackGap: trackGap,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Clip is only needed with indeterminate progress indicators
|
||||
if (borderRadius != null && widget.value == null) {
|
||||
result = ClipRRect(
|
||||
borderRadius: borderRadius,
|
||||
child: result,
|
||||
);
|
||||
}
|
||||
|
||||
return widget._buildSemanticsWrapper(
|
||||
context: context,
|
||||
child: Container(
|
||||
// Clip is only needed with indeterminate progress indicators
|
||||
clipBehavior: (widget.borderRadius != BorderRadius.zero && widget.value == null)
|
||||
? Clip.antiAlias
|
||||
: Clip.none,
|
||||
decoration: ShapeDecoration(
|
||||
color: trackColor,
|
||||
shape: RoundedRectangleBorder(borderRadius: widget.borderRadius),
|
||||
),
|
||||
constraints: BoxConstraints(
|
||||
minWidth: double.infinity,
|
||||
minHeight: minHeight,
|
||||
),
|
||||
child: CustomPaint(
|
||||
painter: _LinearProgressIndicatorPainter(
|
||||
backgroundColor: trackColor,
|
||||
valueColor: widget._getValueColor(context, defaultColor: defaults.color),
|
||||
value: widget.value, // may be null
|
||||
animationValue: animationValue, // ignored if widget.value is not null
|
||||
textDirection: textDirection,
|
||||
indicatorBorderRadius: widget.borderRadius,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: result,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1065,6 +1200,22 @@ class _LinearProgressIndicatorDefaultsM2 extends ProgressIndicatorThemeData {
|
||||
double get linearMinHeight => 4.0;
|
||||
}
|
||||
|
||||
class _LinearProgressIndicatorDefaultsM3Year2023 extends ProgressIndicatorThemeData {
|
||||
_LinearProgressIndicatorDefaultsM3Year2023(this.context);
|
||||
|
||||
final BuildContext context;
|
||||
late final ColorScheme _colors = Theme.of(context).colorScheme;
|
||||
|
||||
@override
|
||||
Color get color => _colors.primary;
|
||||
|
||||
@override
|
||||
Color get linearTrackColor => _colors.secondaryContainer;
|
||||
|
||||
@override
|
||||
double get linearMinHeight => 4.0;
|
||||
}
|
||||
|
||||
// BEGIN GENERATED TOKEN PROPERTIES - ProgressIndicator
|
||||
|
||||
// Do not edit by hand. The code between the "BEGIN GENERATED" and
|
||||
@ -1099,6 +1250,18 @@ class _LinearProgressIndicatorDefaultsM3 extends ProgressIndicatorThemeData {
|
||||
|
||||
@override
|
||||
double get linearMinHeight => 4.0;
|
||||
|
||||
@override
|
||||
BorderRadius get borderRadius => BorderRadius.circular(4.0 / 2);
|
||||
|
||||
@override
|
||||
Color get stopIndicatorColor => _colors.primary;
|
||||
|
||||
@override
|
||||
double? get stopIndicatorRadius => 4.0 / 2;
|
||||
|
||||
@override
|
||||
double? get trackGap => 4.0;
|
||||
}
|
||||
|
||||
// END GENERATED TOKEN PROPERTIES - ProgressIndicator
|
||||
|
@ -39,6 +39,10 @@ class ProgressIndicatorThemeData with Diagnosticable {
|
||||
this.linearMinHeight,
|
||||
this.circularTrackColor,
|
||||
this.refreshBackgroundColor,
|
||||
this.borderRadius,
|
||||
this.stopIndicatorColor,
|
||||
this.stopIndicatorRadius,
|
||||
this.trackGap,
|
||||
});
|
||||
|
||||
/// The color of the [ProgressIndicator]'s indicator.
|
||||
@ -66,6 +70,27 @@ class ProgressIndicatorThemeData with Diagnosticable {
|
||||
/// {@macro flutter.material.RefreshProgressIndicator.backgroundColor}
|
||||
final Color? refreshBackgroundColor;
|
||||
|
||||
/// Overrides the border radius of the [ProgressIndicator].
|
||||
final BorderRadiusGeometry? borderRadius;
|
||||
|
||||
/// Overrides the stop indicator color of the [LinearProgressIndicator].
|
||||
///
|
||||
/// If [LinearProgressIndicator.year2023] is false or [ThemeData.useMaterial3]
|
||||
/// is false, then no stop indicator will be drawn.
|
||||
final Color? stopIndicatorColor;
|
||||
|
||||
/// Overrides the stop indicator radius of the [LinearProgressIndicator].
|
||||
///
|
||||
/// If [LinearProgressIndicator.year2023] is false or [ThemeData.useMaterial3]
|
||||
/// is false, then no stop indicator will be drawn.
|
||||
final double? stopIndicatorRadius;
|
||||
|
||||
/// Overrides the gap between the [LinearProgressIndicator].
|
||||
///
|
||||
/// If [LinearProgressIndicator.year2023] is false or [ThemeData.useMaterial3]
|
||||
/// is false, then no track gap will be drawn.
|
||||
final double? trackGap;
|
||||
|
||||
/// Creates a copy of this object but with the given fields replaced with the
|
||||
/// new values.
|
||||
ProgressIndicatorThemeData copyWith({
|
||||
@ -74,6 +99,10 @@ class ProgressIndicatorThemeData with Diagnosticable {
|
||||
double? linearMinHeight,
|
||||
Color? circularTrackColor,
|
||||
Color? refreshBackgroundColor,
|
||||
BorderRadiusGeometry? borderRadius,
|
||||
Color? stopIndicatorColor,
|
||||
double? stopIndicatorRadius,
|
||||
double? trackGap,
|
||||
}) {
|
||||
return ProgressIndicatorThemeData(
|
||||
color: color ?? this.color,
|
||||
@ -81,6 +110,10 @@ class ProgressIndicatorThemeData with Diagnosticable {
|
||||
linearMinHeight : linearMinHeight ?? this.linearMinHeight,
|
||||
circularTrackColor : circularTrackColor ?? this.circularTrackColor,
|
||||
refreshBackgroundColor : refreshBackgroundColor ?? this.refreshBackgroundColor,
|
||||
borderRadius : borderRadius ?? this.borderRadius,
|
||||
stopIndicatorColor : stopIndicatorColor ?? this.stopIndicatorColor,
|
||||
stopIndicatorRadius : stopIndicatorRadius ?? this.stopIndicatorRadius,
|
||||
trackGap : trackGap ?? this.trackGap,
|
||||
);
|
||||
}
|
||||
|
||||
@ -97,6 +130,10 @@ class ProgressIndicatorThemeData with Diagnosticable {
|
||||
linearMinHeight : lerpDouble(a?.linearMinHeight, b?.linearMinHeight, t),
|
||||
circularTrackColor : Color.lerp(a?.circularTrackColor, b?.circularTrackColor, t),
|
||||
refreshBackgroundColor : Color.lerp(a?.refreshBackgroundColor, b?.refreshBackgroundColor, t),
|
||||
borderRadius : BorderRadiusGeometry.lerp(a?.borderRadius, b?.borderRadius, t),
|
||||
stopIndicatorColor : Color.lerp(a?.stopIndicatorColor, b?.stopIndicatorColor, t),
|
||||
stopIndicatorRadius : lerpDouble(a?.stopIndicatorRadius, b?.stopIndicatorRadius, t),
|
||||
trackGap : lerpDouble(a?.trackGap, b?.trackGap, t),
|
||||
);
|
||||
}
|
||||
|
||||
@ -107,6 +144,10 @@ class ProgressIndicatorThemeData with Diagnosticable {
|
||||
linearMinHeight,
|
||||
circularTrackColor,
|
||||
refreshBackgroundColor,
|
||||
borderRadius,
|
||||
stopIndicatorColor,
|
||||
stopIndicatorRadius,
|
||||
trackGap,
|
||||
);
|
||||
|
||||
@override
|
||||
@ -122,7 +163,11 @@ class ProgressIndicatorThemeData with Diagnosticable {
|
||||
&& other.linearTrackColor == linearTrackColor
|
||||
&& other.linearMinHeight == linearMinHeight
|
||||
&& other.circularTrackColor == circularTrackColor
|
||||
&& other.refreshBackgroundColor == refreshBackgroundColor;
|
||||
&& other.refreshBackgroundColor == refreshBackgroundColor
|
||||
&& other.borderRadius == borderRadius
|
||||
&& other.stopIndicatorColor == stopIndicatorColor
|
||||
&& other.stopIndicatorRadius == stopIndicatorRadius
|
||||
&& other.trackGap == trackGap;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -133,6 +178,10 @@ class ProgressIndicatorThemeData with Diagnosticable {
|
||||
properties.add(DoubleProperty('linearMinHeight', linearMinHeight, defaultValue: null));
|
||||
properties.add(ColorProperty('circularTrackColor', circularTrackColor, defaultValue: null));
|
||||
properties.add(ColorProperty('refreshBackgroundColor', refreshBackgroundColor, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<BorderRadiusGeometry>('borderRadius', borderRadius, defaultValue: null));
|
||||
properties.add(ColorProperty('stopIndicatorColor', stopIndicatorColor, defaultValue: null));
|
||||
properties.add(DoubleProperty('stopIndicatorRadius', stopIndicatorRadius, defaultValue: null));
|
||||
properties.add(DoubleProperty('trackGap', trackGap, defaultValue: null));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1300,6 +1300,257 @@ void main() {
|
||||
expect(padding.padding, testIndicatorMargin);
|
||||
expect(innerPadding.padding, testIndicatorPadding);
|
||||
});
|
||||
|
||||
testWidgets('LinearProgressIndicator default stop indicator when year2023 is false', (WidgetTester tester) async {
|
||||
Widget buildIndicator({ required TextDirection textDirection }) {
|
||||
return Directionality(
|
||||
textDirection: textDirection,
|
||||
child: const Center(
|
||||
child: SizedBox(
|
||||
width: 200.0,
|
||||
child: LinearProgressIndicator(
|
||||
year2023: false,
|
||||
value: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildIndicator(textDirection: TextDirection.ltr));
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
paints..circle(x: 198.0, y: 2.0, radius: 2.0, color: theme.colorScheme.primary),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(buildIndicator(textDirection: TextDirection.rtl));
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
paints..circle(x: 2.0, y: 2.0, radius: 2.0, color: theme.colorScheme.primary)
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Indeterminate LinearProgressIndicator does not paint stop indicator', (WidgetTester tester) async {
|
||||
Widget buildIndicator({ double? value }) {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: 200.0,
|
||||
child: LinearProgressIndicator(
|
||||
year2023: false,
|
||||
value: value,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Determinate LinearProgressIndicator paints stop indicator.
|
||||
await tester.pumpWidget(buildIndicator(value: 0.5));
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
// Stop indicator.
|
||||
paints..circle(x: 198.0, y: 2.0, radius: 2.0, color: theme.colorScheme.primary),
|
||||
);
|
||||
|
||||
// Indeterminate LinearProgressIndicator does not paint stop indicator.
|
||||
await tester.pumpWidget(buildIndicator());
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
// Stop indicator.
|
||||
isNot(paints..circle(x: 198.0, y: 2.0, radius: 2.0, color: theme.colorScheme.primary)),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can customise LinearProgressIndicator stop indicator when year2023 is false', (WidgetTester tester) async {
|
||||
const Color stopIndicatorColor = Color(0XFF00FF00);
|
||||
const double stopIndicatorRadius = 5.0;
|
||||
Widget buildIndicator({ Color? stopIndicatorColor, double? stopIndicatorRadius }) {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: 200.0,
|
||||
child: LinearProgressIndicator(
|
||||
year2023: false,
|
||||
stopIndicatorColor: stopIndicatorColor,
|
||||
stopIndicatorRadius: stopIndicatorRadius,
|
||||
minHeight: 20.0,
|
||||
value: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Test customized stop indicator.
|
||||
await tester.pumpWidget(buildIndicator(
|
||||
stopIndicatorColor: stopIndicatorColor,
|
||||
stopIndicatorRadius: stopIndicatorRadius,
|
||||
));
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
// Stop indicator.
|
||||
paints..circle(x: 190.0, y: 10.0, radius: stopIndicatorRadius, color: stopIndicatorColor),
|
||||
);
|
||||
|
||||
// Remove stop indicator.
|
||||
await tester.pumpWidget(buildIndicator(stopIndicatorRadius: 0));
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
// Stop indicator.
|
||||
isNot(paints..circle(color: stopIndicatorColor)),
|
||||
);
|
||||
|
||||
// Test stop indicator with transparent color.
|
||||
await tester.pumpWidget(buildIndicator(stopIndicatorColor: const Color(0x00000000)));
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
// Stop indicator.
|
||||
paints..circle(color: const Color(0x00000000)),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Stop indicator size cannot be larger than the progress indicator', (WidgetTester tester) async {
|
||||
Widget buildIndicator({ double? stopIndicatorRadius, double? minHeight }) {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: 200.0,
|
||||
child: LinearProgressIndicator(
|
||||
year2023: false,
|
||||
stopIndicatorRadius: stopIndicatorRadius,
|
||||
minHeight: minHeight,
|
||||
value: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Test stop indicator radius equals to minHeight.
|
||||
await tester.pumpWidget(buildIndicator(stopIndicatorRadius: 10.0, minHeight: 20.0));
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
paints..circle(x: 190.0, y: 10.0, radius: 10.0, color: theme.colorScheme.primary),
|
||||
);
|
||||
|
||||
// Test stop indicator radius larger than minHeight.
|
||||
await tester.pumpWidget(buildIndicator(stopIndicatorRadius: 30.0, minHeight: 20.0));
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
// Stop indicator radius is clamped to minHeight.
|
||||
paints..circle(x: 190.0, y: 10.0, radius: 10.0, color: theme.colorScheme.primary),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('LinearProgressIndicator default track gap when year2023 is false', (WidgetTester tester) async {
|
||||
const double defaultTrackGap = 4.0;
|
||||
Widget buildIndicator({ required TextDirection textDirection }) {
|
||||
return Directionality(
|
||||
textDirection: textDirection,
|
||||
child: const Center(
|
||||
child: SizedBox(
|
||||
width: 200.0,
|
||||
child: LinearProgressIndicator(
|
||||
year2023: false,
|
||||
value: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Test default track gap in LTR.
|
||||
await tester.pumpWidget(buildIndicator(textDirection: TextDirection.ltr));
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
paints
|
||||
// Track.
|
||||
..rrect(
|
||||
rrect: RRect.fromLTRBR(100.0 + defaultTrackGap, 0.0, 200.0, 4.0, const Radius.circular(2.0)),
|
||||
color: theme.colorScheme.secondaryContainer,
|
||||
)
|
||||
// Active track.
|
||||
..rrect(
|
||||
rrect: RRect.fromLTRBR(0.0, 0.0, 100.0, 4.0, const Radius.circular(2.0)),
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
);
|
||||
|
||||
// Test default track gap in RTL.
|
||||
await tester.pumpWidget(buildIndicator(textDirection: TextDirection.rtl));
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
paints
|
||||
// Track.
|
||||
..rrect(
|
||||
rrect: RRect.fromLTRBR(0.0, 0.0, 100.0 - defaultTrackGap, 4.0, const Radius.circular(2.0)),
|
||||
color: theme.colorScheme.secondaryContainer,
|
||||
)
|
||||
// Active track.
|
||||
..rrect(
|
||||
rrect: RRect.fromLTRBR(100.0, 0.0, 200.0, 4.0, const Radius.circular(2.0)),
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can customise LinearProgressIndicator track gap when year2023 is false', (WidgetTester tester) async {
|
||||
const double customTrackGap = 12.0;
|
||||
const double noTrackGap = 0.0;
|
||||
Widget buildIndicator({ double? trackGap }) {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: 200.0,
|
||||
child: LinearProgressIndicator(
|
||||
year2023: false,
|
||||
trackGap: trackGap,
|
||||
value: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Test customized track gap.
|
||||
await tester.pumpWidget(buildIndicator(trackGap: customTrackGap));
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
paints
|
||||
// Track.
|
||||
..rrect(
|
||||
rrect: RRect.fromLTRBR(100.0 + customTrackGap, 0.0, 200.0, 4.0, const Radius.circular(2.0)),
|
||||
color: theme.colorScheme.secondaryContainer,
|
||||
)
|
||||
// Active track.
|
||||
..rrect(
|
||||
rrect: RRect.fromLTRBR(0.0, 0.0, 100.0, 4.0, const Radius.circular(2.0)),
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
);
|
||||
|
||||
// Remove track gap.
|
||||
await tester.pumpWidget(buildIndicator(trackGap: noTrackGap));
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
paints
|
||||
// Track.
|
||||
..rrect(
|
||||
rrect: RRect.fromLTRBR(0.0, 0.0, 200.0, 4.0, const Radius.circular(2.0)),
|
||||
color: theme.colorScheme.secondaryContainer,
|
||||
)
|
||||
// Active indicator.
|
||||
..rrect(
|
||||
rrect: RRect.fromLTRBR(0.0, 0.0, 100.0, 4.0, const Radius.circular(2.0)),
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
class _RefreshProgressIndicatorGolden extends StatefulWidget {
|
||||
|
@ -16,4 +16,170 @@ void main() {
|
||||
const ProgressIndicatorThemeData data = ProgressIndicatorThemeData();
|
||||
expect(identical(ProgressIndicatorThemeData.lerp(data, data, 0.5), data), true);
|
||||
});
|
||||
|
||||
testWidgets('Can theme LinearProgressIndicator using ProgressIndicatorTheme', (WidgetTester tester) async {
|
||||
const Color color = Color(0XFF00FF00);
|
||||
const Color linearTrackColor = Color(0XFFFF0000);
|
||||
const double linearMinHeight = 25.0;
|
||||
const double borderRadius = 8.0;
|
||||
final ThemeData theme = ThemeData(
|
||||
progressIndicatorTheme: ProgressIndicatorThemeData(
|
||||
color: color,
|
||||
linearTrackColor: linearTrackColor,
|
||||
linearMinHeight: linearMinHeight,
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
),
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: theme,
|
||||
home: const Scaffold(
|
||||
body: Center(
|
||||
child: SizedBox(
|
||||
width: 200.0,
|
||||
child: LinearProgressIndicator(
|
||||
value: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
paints
|
||||
// Track.
|
||||
..rrect(
|
||||
rrect: RRect.fromLTRBR(0.0, 0.0, 200.0, linearMinHeight, const Radius.circular(borderRadius)),
|
||||
color: linearTrackColor,
|
||||
)
|
||||
// Active indicator.
|
||||
..rrect(
|
||||
rrect: RRect.fromLTRBR(0.0, 0.0, 100.0, linearMinHeight, const Radius.circular(borderRadius)),
|
||||
color: color,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Can theme LinearProgressIndicator with year2023 to false', (WidgetTester tester) async {
|
||||
const Color color = Color(0XFF00FF00);
|
||||
const Color linearTrackColor = Color(0XFFFF0000);
|
||||
const double linearMinHeight = 25.0;
|
||||
const double borderRadius = 8.0;
|
||||
const Color stopIndicatorColor = Color(0XFF0000FF);
|
||||
const double stopIndicatorRadius = 10.0;
|
||||
const double trackGap = 16.0;
|
||||
final ThemeData theme = ThemeData(
|
||||
progressIndicatorTheme: ProgressIndicatorThemeData(
|
||||
color: color,
|
||||
linearTrackColor: linearTrackColor,
|
||||
linearMinHeight: linearMinHeight,
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
stopIndicatorColor: stopIndicatorColor,
|
||||
stopIndicatorRadius: stopIndicatorRadius,
|
||||
trackGap: trackGap,
|
||||
),
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: theme,
|
||||
home: const Scaffold(
|
||||
body: Center(
|
||||
child: SizedBox(
|
||||
width: 200.0,
|
||||
child: LinearProgressIndicator(
|
||||
year2023: false,
|
||||
value: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
paints
|
||||
// Track.
|
||||
..rrect(
|
||||
rrect: RRect.fromLTRBR(100.0 + trackGap, 0.0, 200.0, linearMinHeight, const Radius.circular(borderRadius)),
|
||||
color: linearTrackColor,
|
||||
)
|
||||
// Stop indicator.
|
||||
..circle(
|
||||
x: 187.5,
|
||||
y: 12.5,
|
||||
radius: stopIndicatorRadius,
|
||||
color: stopIndicatorColor,
|
||||
)
|
||||
// Active indicator.
|
||||
..rrect(
|
||||
rrect: RRect.fromLTRBR(0.0, 0.0, 100.0, linearMinHeight, const Radius.circular(borderRadius)),
|
||||
color: color,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Local ProgressIndicatorTheme takes precedence over inherited ProgressIndicatorTheme', (WidgetTester tester) async {
|
||||
const Color color = Color(0XFFFF00FF);
|
||||
const Color linearTrackColor = Color(0XFF00FFFF);
|
||||
const double linearMinHeight = 20.0;
|
||||
const double borderRadius = 6.0;
|
||||
const Color stopIndicatorColor = Color(0XFFFFFF00);
|
||||
const double stopIndicatorRadius = 8.0;
|
||||
const double trackGap = 12.0;
|
||||
final ThemeData theme = ThemeData(
|
||||
progressIndicatorTheme: const ProgressIndicatorThemeData(
|
||||
color: Color(0XFF00FF00),
|
||||
linearTrackColor: Color(0XFFFF0000),
|
||||
linearMinHeight: 25.0,
|
||||
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
||||
stopIndicatorColor: Color(0XFF0000FF),
|
||||
stopIndicatorRadius: 10.0,
|
||||
trackGap: 16.0,
|
||||
),
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: theme,
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: ProgressIndicatorTheme(
|
||||
data: ProgressIndicatorThemeData(
|
||||
color: color,
|
||||
linearTrackColor: linearTrackColor,
|
||||
linearMinHeight: linearMinHeight,
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
stopIndicatorColor: stopIndicatorColor,
|
||||
stopIndicatorRadius: stopIndicatorRadius,
|
||||
trackGap: trackGap,
|
||||
),
|
||||
child: const SizedBox(
|
||||
width: 200.0,
|
||||
child: LinearProgressIndicator(
|
||||
value: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(
|
||||
find.byType(LinearProgressIndicator),
|
||||
paints
|
||||
// Track.
|
||||
..rrect(
|
||||
rrect: RRect.fromLTRBR(0.0, 0.0, 200.0, linearMinHeight, const Radius.circular(borderRadius)),
|
||||
color: linearTrackColor,
|
||||
)
|
||||
// Active indicator.
|
||||
..rrect(
|
||||
rrect: RRect.fromLTRBR(0.0, 0.0, 100.0, linearMinHeight, const Radius.circular(borderRadius)),
|
||||
color: color,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user