mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Adds custom control builder functionality to Stepper (#23310)
* Adds test and builder
This commit is contained in:
parent
bc56a7a6c5
commit
60de2deb4d
@ -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(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user