Unverified Commit 60de2deb authored by jslavitz's avatar jslavitz Committed by GitHub

Adds custom control builder functionality to Stepper (#23310)

* Adds test and builder
parent bc56a7a6
......@@ -140,6 +140,7 @@ class Stepper extends StatefulWidget {
this.onStepTapped,
this.onStepContinue,
this.onStepCancel,
this.controlsBuilder,
}) : assert(steps != null),
assert(type != null),
assert(currentStep != null),
......@@ -174,6 +175,53 @@ class Stepper extends StatefulWidget {
/// If null, the 'cancel' button will be disabled.
final VoidCallback onStepCancel;
/// The callback for creating custom controls.
///
/// If null, the default controls from the current theme will be used.
///
/// This callback which takes in a context and two functions,[onStepContinue]
/// and [onStepCancel]. These can be used to control the stepper.
///
/// ## Sample Code:
/// Creates a stepper control with custom buttons.
///
/// ```dart
/// Stepper(
/// controlsBuilder:
/// (BuildContext context, {VoidCallback onStepContinue, VoidCallback onStepCancel}) {
/// return Row(
/// children: <Widget>[
/// FlatButton(
/// onPressed: onStepContinue,
/// child: const Text('My Awesome Continue Message!'),
/// ),
/// FlatButton(
/// onPressed: onStepCancel,
/// child: const Text('My Awesome Cancel Message!'),
/// ),
/// ],
/// ),
/// },
/// steps: const <Step>[
/// Step(
/// title: Text('A'),
/// content: SizedBox(
/// width: 100.0,
/// height: 100.0,
/// ),
/// ),
/// Step(
/// title: Text('B'),
/// content: SizedBox(
/// width: 100.0,
/// height: 100.0,
/// ),
/// ),
/// ],
/// )
/// ```
final ControlsWidgetBuilder controlsBuilder;
@override
_StepperState createState() => _StepperState();
}
......@@ -327,6 +375,9 @@ class _StepperState extends State<Stepper> with TickerProviderStateMixin {
}
Widget _buildVerticalControls() {
if (widget.controlsBuilder != null)
return widget.controlsBuilder(context, onStepContinue: widget.onStepContinue, onStepCancel: widget.onStepCancel);
Color cancelColor;
switch (Theme.of(context).brightness) {
......
......@@ -3632,6 +3632,11 @@ typedef IndexedWidgetBuilder = Widget Function(BuildContext context, int index);
/// [MaterialApp.builder].
typedef TransitionBuilder = Widget Function(BuildContext context, Widget child);
/// A Signiture for a function that creates a widget given [onStepContinue] and [onStepCancel].
///
/// Used by [Stepper.builder].
typedef ControlsWidgetBuilder = Widget Function(BuildContext context, {VoidCallback onStepContinue, VoidCallback onStepCancel});
/// An [Element] that composes other [Element]s.
///
/// Rather than creating a [RenderObject] directly, a [ComponentElement] creates
......
......@@ -368,6 +368,91 @@ void main() {
expect(find.text('2'), findsOneWidget);
});
testWidgets('Stepper custom controls test', (WidgetTester tester) async {
bool continuePressed = false;
void setContinue() {
continuePressed = true;
}
bool canceledPressed = false;
void setCanceled() {
canceledPressed = true;
}
final ControlsWidgetBuilder builder =
(BuildContext context, {VoidCallback onStepContinue, VoidCallback onStepCancel}) {
return Container(
margin: const EdgeInsets.only(top: 16.0),
child: ConstrainedBox(
constraints: const BoxConstraints.tightFor(height: 48.0),
child: Row(
children: <Widget>[
FlatButton(
onPressed: onStepContinue,
color: Colors.blue,
textColor: Colors.white,
textTheme: ButtonTextTheme.normal,
child: const Text('Let us continue!'),
),
Container(
margin: const EdgeInsetsDirectional.only(start: 8.0),
child: FlatButton(
onPressed: onStepCancel,
textColor: Colors.red,
textTheme: ButtonTextTheme.normal,
child: const Text('Cancel This!'),
),
),
],
),
),
);
};
await tester.pumpWidget(
MaterialApp(
home: Center(
child: Material(
child: Stepper(
controlsBuilder: builder,
onStepCancel: setCanceled,
onStepContinue: setContinue,
steps: const <Step>[
Step(
title: Text('A'),
state: StepState.complete,
content: SizedBox(
width: 100.0,
height: 100.0,
),
),
Step(
title: Text('B'),
content: SizedBox(
width: 100.0,
height: 100.0,
),
),
],
),
),
),
),
);
// 2 because stepper creates a set of controls for each step
expect(find.text('Let us continue!'), findsNWidgets(2));
expect(find.text('Cancel This!'), findsNWidgets(2));
await tester.tap(find.text('Cancel This!').first);
await tester.pumpAndSettle();
await tester.tap(find.text('Let us continue!').first);
await tester.pumpAndSettle();
expect(canceledPressed, isTrue);
expect(continuePressed, isTrue);
});
testWidgets('Stepper error test', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
......
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