Unverified Commit 0d68fccc authored by jslavitz's avatar jslavitz Committed by GitHub

Add DropDownButtonFormField convenience class (#23611)

* Adds DropDownFormField Convenience Class
parent fd6b2e19
...@@ -12,6 +12,7 @@ import 'constants.dart'; ...@@ -12,6 +12,7 @@ import 'constants.dart';
import 'debug.dart'; import 'debug.dart';
import 'icons.dart'; import 'icons.dart';
import 'ink_well.dart'; import 'ink_well.dart';
import 'input_decorator.dart';
import 'material.dart'; import 'material.dart';
import 'material_localizations.dart'; import 'material_localizations.dart';
import 'scrollbar.dart'; import 'scrollbar.dart';
...@@ -763,3 +764,62 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi ...@@ -763,3 +764,62 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
); );
} }
} }
/// A convenience widget that wraps a [DropdownButton] in a [FormField].
class DropdownButtonFormField<T> extends FormField<T> {
/// Creates a [DropdownButton] widget wrapped in an [InputDecorator] and
/// [FormField].
///
/// The [DropdownButton] [items] parameters must not be null.
DropdownButtonFormField({
Key key,
T value,
@required List<DropdownMenuItem<T>> items,
this.onChanged,
InputDecoration decoration = const InputDecoration(),
FormFieldSetter<T> onSaved,
FormFieldValidator<T> validator,
Widget hint,
}) : assert(decoration != null),
super(
key: key,
onSaved: onSaved,
initialValue: value,
validator: validator,
builder: (FormFieldState<T> field) {
final InputDecoration effectiveDecoration = decoration
.applyDefaults(Theme.of(field.context).inputDecorationTheme);
return InputDecorator(
decoration: effectiveDecoration.copyWith(errorText: field.errorText),
isEmpty: value == null,
child: DropdownButtonHideUnderline(
child: DropdownButton<T>(
isDense: true,
value: value,
items: items,
hint: hint,
onChanged: field.didChange,
),
),
);
}
);
/// Called when the user selects an item.
final ValueChanged<T> onChanged;
@override
FormFieldState<T> createState() => _DropdownButtonFormFieldState<T>();
}
class _DropdownButtonFormFieldState<T> extends FormFieldState<T> {
@override
DropdownButtonFormField<T> get widget => super.widget;
@override
void didChange(T value) {
super.didChange(value);
if (widget.onChanged != null)
widget.onChanged(value);
}
}
...@@ -237,6 +237,48 @@ void main() { ...@@ -237,6 +237,48 @@ void main() {
expect(value, equals('two')); expect(value, equals('two'));
}); });
testWidgets('Dropdown form field', (WidgetTester tester) async {
String value = 'one';
await tester.pumpWidget(
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return MaterialApp(
home: Material(
child: DropdownButtonFormField<String>(
value: value,
hint: const Text('Select Value'),
decoration: const InputDecoration(
prefixIcon: Icon(Icons.fastfood)
),
items: menuItems.map((String val) {
return DropdownMenuItem<String>(
value: val,
child: Text(val)
);
}).toList(),
onChanged: (String v) {
setState(() {
value = v;
});
},
validator: (String v) => v == null ? 'Must select value' : null,
),
),
);
}
)
);
expect(value, equals('one'));
await tester.tap(find.text('one'));
await tester.pumpAndSettle();
await tester.tap(find.text('three').last);
await tester.pump();
await tester.pumpAndSettle();
expect(value, equals('three'));
});
testWidgets('Dropdown in ListView', (WidgetTester tester) async { testWidgets('Dropdown in ListView', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/12053 // Regression test for https://github.com/flutter/flutter/issues/12053
// Positions a DropdownButton at the left and right edges of the screen, // Positions a DropdownButton at the left and right edges of the screen,
......
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