mirror of
https://github.com/flutter/flutter
synced 2024-08-27 20:10:11 +00:00
[Stepper] adds stepIconBuilder property (#122816)
[Stepper] adds stepIconBuilder property
This commit is contained in:
parent
d74a1bb012
commit
91311156e1
|
@ -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:
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue