[Stepper] adds stepIconBuilder property (#122816)

[Stepper] adds stepIconBuilder property
This commit is contained in:
Ayush Bherwani 2023-03-29 12:46:01 +05:30 committed by GitHub
parent d74a1bb012
commit 91311156e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 60 additions and 1 deletions

View file

@ -106,6 +106,10 @@ class ControlsDetails {
/// * [WidgetBuilder], which is similar but only takes a [BuildContext].
typedef ControlsWidgetBuilder = Widget Function(BuildContext context, ControlsDetails details);
/// A builder that creates the icon widget for the [Step] at [stepIndex], given
/// [stepState].
typedef StepIconBuilder = Widget? Function(int stepIndex, StepState stepState);
const TextStyle _kStepStyle = TextStyle(
fontSize: 12.0,
color: Colors.white,
@ -207,6 +211,7 @@ class Stepper extends StatefulWidget {
this.controlsBuilder,
this.elevation,
this.margin,
this.stepIconBuilder,
}) : assert(0 <= currentStep && currentStep < steps.length);
/// The steps of the stepper whose titles, subtitles, icons always get shown.
@ -303,9 +308,17 @@ class Stepper extends StatefulWidget {
/// The elevation of this stepper's [Material] when [type] is [StepperType.horizontal].
final double? elevation;
/// custom margin on vertical stepper.
/// Custom margin on vertical stepper.
final EdgeInsetsGeometry? margin;
/// Callback for creating custom icons for the [steps].
///
/// When overriding icon for [StepState.error], please return
/// a widget whose width and height are 14 pixels or less to avoid overflow.
///
/// If null, the default icons will be used for respective [StepState].
final StepIconBuilder? stepIconBuilder;
@override
State<Stepper> createState() => _StepperState();
}
@ -373,6 +386,10 @@ class _StepperState extends State<Stepper> with TickerProviderStateMixin {
Widget _buildCircleChild(int index, bool oldState) {
final StepState state = oldState ? _oldStates[index]! : widget.steps[index].state;
final bool isDarkActive = _isDark() && widget.steps[index].isActive;
final Widget? icon = widget.stepIconBuilder?.call(index, state);
if (icon != null) {
return icon;
}
switch (state) {
case StepState.indexed:
case StepState.disabled:

View file

@ -1259,6 +1259,48 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async
tester.widget<Text>(find.text('Label ${index + 2}'));
expect(bodyMediumStyle, nextLabelTextWidget.style);
});
testWidgets('Stepper stepIconBuilder test', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Stepper(
stepIconBuilder: (int index, StepState state) {
if (state == StepState.complete) {
return const FlutterLogo(size: 18);
}
return null;
},
steps: const <Step>[
Step(
title: Text('A'),
state: StepState.complete,
content: SizedBox(width: 100.0, height: 100.0),
),
Step(
title: Text('B'),
state: StepState.editing,
content: SizedBox(width: 100.0, height: 100.0),
),
Step(
title: Text('C'),
state: StepState.error,
content: SizedBox(width: 100.0, height: 100.0),
),
],
),
),
),
);
/// Finds the overridden widget for StepState.complete
expect(find.byType(FlutterLogo), findsOneWidget);
/// StepState.editing and StepState.error should have a default icon
expect(find.byIcon(Icons.edit), findsOneWidget);
expect(find.text('!'), findsOneWidget);
});
}
class _TappableColorWidget extends StatefulWidget {