Fix autocomplete options height (#80187)
This commit is contained in:
@@ -166,6 +166,7 @@ class Autocomplete<T extends Object> extends StatelessWidget {
|
||||
this.displayStringForOption = RawAutocomplete.defaultStringForOption,
|
||||
this.fieldViewBuilder = _defaultFieldViewBuilder,
|
||||
this.onSelected,
|
||||
this.optionsMaxHeight = 200.0,
|
||||
this.optionsViewBuilder,
|
||||
this.initialValue,
|
||||
}) : assert(displayStringForOption != null),
|
||||
@@ -193,6 +194,14 @@ class Autocomplete<T extends Object> extends StatelessWidget {
|
||||
/// default.
|
||||
final AutocompleteOptionsViewBuilder<T>? optionsViewBuilder;
|
||||
|
||||
/// The maximum height used for the default Material options list widget.
|
||||
///
|
||||
/// When [optionsViewBuilder] is `null`, this property sets the maximum height
|
||||
/// that the options widget can occupy.
|
||||
///
|
||||
/// The default value is set to 200.
|
||||
final double optionsMaxHeight;
|
||||
|
||||
/// {@macro flutter.widgets.RawAutocomplete.initialValue}
|
||||
final TextEditingValue? initialValue;
|
||||
|
||||
@@ -216,6 +225,7 @@ class Autocomplete<T extends Object> extends StatelessWidget {
|
||||
displayStringForOption: displayStringForOption,
|
||||
onSelected: onSelected,
|
||||
options: options,
|
||||
maxOptionsHeight: optionsMaxHeight,
|
||||
);
|
||||
},
|
||||
onSelected: onSelected,
|
||||
@@ -257,6 +267,7 @@ class _AutocompleteOptions<T extends Object> extends StatelessWidget {
|
||||
required this.displayStringForOption,
|
||||
required this.onSelected,
|
||||
required this.options,
|
||||
required this.maxOptionsHeight,
|
||||
}) : super(key: key);
|
||||
|
||||
final AutocompleteOptionToString<T> displayStringForOption;
|
||||
@@ -264,6 +275,7 @@ class _AutocompleteOptions<T extends Object> extends StatelessWidget {
|
||||
final AutocompleteOnSelected<T> onSelected;
|
||||
|
||||
final Iterable<T> options;
|
||||
final double maxOptionsHeight;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -271,10 +283,11 @@ class _AutocompleteOptions<T extends Object> extends StatelessWidget {
|
||||
alignment: Alignment.topLeft,
|
||||
child: Material(
|
||||
elevation: 4.0,
|
||||
child: SizedBox(
|
||||
height: 200.0,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: maxOptionsHeight),
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
itemCount: options.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final T option = options.elementAt(index);
|
||||
|
||||
@@ -254,6 +254,104 @@ void main() {
|
||||
expect(find.byKey(optionsKey), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('the default Autocomplete options widget has a maximum height of 200', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(MaterialApp(home: Scaffold(
|
||||
body: Autocomplete<String>(
|
||||
optionsBuilder: (TextEditingValue textEditingValue) {
|
||||
return kOptions.where((String option) {
|
||||
return option.contains(textEditingValue.text.toLowerCase());
|
||||
});
|
||||
},
|
||||
),
|
||||
)));
|
||||
|
||||
final Finder listFinder = find.byType(ListView);
|
||||
final Finder inputFinder = find.byType(TextFormField);
|
||||
await tester.tap(inputFinder);
|
||||
await tester.enterText(inputFinder, '');
|
||||
await tester.pump();
|
||||
final Size baseSize = tester.getSize(listFinder);
|
||||
final double resultingHeight = baseSize.height;
|
||||
expect(resultingHeight, equals(200));
|
||||
});
|
||||
|
||||
testWidgets('the options height restricts to max desired height', (WidgetTester tester) async {
|
||||
const double desiredHeight = 150.0;
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Autocomplete<String>(
|
||||
optionsMaxHeight: desiredHeight,
|
||||
optionsBuilder: (TextEditingValue textEditingValue) {
|
||||
return kOptions.where((String option) {
|
||||
return option.contains(textEditingValue.text.toLowerCase());
|
||||
});
|
||||
},
|
||||
),
|
||||
)));
|
||||
|
||||
/// entering "a" returns 9 items from kOptions so basically the
|
||||
/// height of 9 options would be beyond `desiredHeight=150`,
|
||||
/// so height gets restricted to desiredHeight.
|
||||
final Finder listFinder = find.byType(ListView);
|
||||
final Finder inputFinder = find.byType(TextFormField);
|
||||
await tester.tap(inputFinder);
|
||||
await tester.enterText(inputFinder, 'a');
|
||||
await tester.pump();
|
||||
final Size baseSize = tester.getSize(listFinder);
|
||||
final double resultingHeight = baseSize.height;
|
||||
|
||||
/// expected desired Height =150.0
|
||||
expect(resultingHeight, equals(desiredHeight));
|
||||
});
|
||||
|
||||
testWidgets('The height of options shrinks to height of resulting items, if less than maxHeight', (WidgetTester tester) async {
|
||||
// Returns a Future with the height of the default [Autocomplete] options widget
|
||||
// after the provided text had been entered into the [Autocomplete] field.
|
||||
Future<double> _getDefaultOptionsHeight(
|
||||
WidgetTester tester, String enteredText) async {
|
||||
final Finder listFinder = find.byType(ListView);
|
||||
final Finder inputFinder = find.byType(TextFormField);
|
||||
final TextFormField field = inputFinder.evaluate().first.widget as TextFormField;
|
||||
field.controller!.clear();
|
||||
await tester.tap(inputFinder);
|
||||
await tester.enterText(inputFinder, enteredText);
|
||||
await tester.pump();
|
||||
final Size baseSize = tester.getSize(listFinder);
|
||||
return baseSize.height;
|
||||
}
|
||||
|
||||
const double maxOptionsHeight = 250.0;
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Autocomplete<String>(
|
||||
optionsMaxHeight: maxOptionsHeight,
|
||||
optionsBuilder: (TextEditingValue textEditingValue) {
|
||||
return kOptions.where((String option) {
|
||||
return option.contains(textEditingValue.text.toLowerCase());
|
||||
});
|
||||
},
|
||||
),
|
||||
)));
|
||||
|
||||
final Finder listFinder = find.byType(ListView);
|
||||
expect(listFinder, findsNothing);
|
||||
|
||||
/// entering `a` returns 9 items(height > `maxOptionsheight`) from the kOptions
|
||||
/// so height gets restricted to `maxOptionsheight =250`
|
||||
final double nineItemsHeight = await _getDefaultOptionsHeight(tester, 'a');
|
||||
expect(nineItemsHeight, equals(maxOptionsHeight));
|
||||
|
||||
/// returns 2 Items (height < `maxOptionsHeight`)
|
||||
/// so options height shrinks to 2 Items combined height
|
||||
final double twoItemsHeight = await _getDefaultOptionsHeight(tester, 'el');
|
||||
expect(twoItemsHeight, lessThan(maxOptionsHeight));
|
||||
|
||||
/// returns 1 item (height < `maxOptionsHeight`) from `kOptions`
|
||||
/// so options height shrinks to 1 items height
|
||||
final double oneItemsHeight = await _getDefaultOptionsHeight(tester, 'elep');
|
||||
expect(oneItemsHeight, lessThan(twoItemsHeight));
|
||||
});
|
||||
|
||||
testWidgets('initialValue sets initial text field value', (WidgetTester tester) async {
|
||||
late String lastSelection;
|
||||
await tester.pumpWidget(
|
||||
|
||||
Reference in New Issue
Block a user