Unverified Commit 238bc4bf authored by Mahesh Jamdade's avatar Mahesh Jamdade Committed by GitHub

Fix autocomplete options height (#80187)

parent 1e35f4c0
...@@ -166,6 +166,7 @@ class Autocomplete<T extends Object> extends StatelessWidget { ...@@ -166,6 +166,7 @@ class Autocomplete<T extends Object> extends StatelessWidget {
this.displayStringForOption = RawAutocomplete.defaultStringForOption, this.displayStringForOption = RawAutocomplete.defaultStringForOption,
this.fieldViewBuilder = _defaultFieldViewBuilder, this.fieldViewBuilder = _defaultFieldViewBuilder,
this.onSelected, this.onSelected,
this.optionsMaxHeight = 200.0,
this.optionsViewBuilder, this.optionsViewBuilder,
this.initialValue, this.initialValue,
}) : assert(displayStringForOption != null), }) : assert(displayStringForOption != null),
...@@ -193,6 +194,14 @@ class Autocomplete<T extends Object> extends StatelessWidget { ...@@ -193,6 +194,14 @@ class Autocomplete<T extends Object> extends StatelessWidget {
/// default. /// default.
final AutocompleteOptionsViewBuilder<T>? optionsViewBuilder; 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} /// {@macro flutter.widgets.RawAutocomplete.initialValue}
final TextEditingValue? initialValue; final TextEditingValue? initialValue;
...@@ -216,6 +225,7 @@ class Autocomplete<T extends Object> extends StatelessWidget { ...@@ -216,6 +225,7 @@ class Autocomplete<T extends Object> extends StatelessWidget {
displayStringForOption: displayStringForOption, displayStringForOption: displayStringForOption,
onSelected: onSelected, onSelected: onSelected,
options: options, options: options,
maxOptionsHeight: optionsMaxHeight,
); );
}, },
onSelected: onSelected, onSelected: onSelected,
...@@ -257,6 +267,7 @@ class _AutocompleteOptions<T extends Object> extends StatelessWidget { ...@@ -257,6 +267,7 @@ class _AutocompleteOptions<T extends Object> extends StatelessWidget {
required this.displayStringForOption, required this.displayStringForOption,
required this.onSelected, required this.onSelected,
required this.options, required this.options,
required this.maxOptionsHeight,
}) : super(key: key); }) : super(key: key);
final AutocompleteOptionToString<T> displayStringForOption; final AutocompleteOptionToString<T> displayStringForOption;
...@@ -264,6 +275,7 @@ class _AutocompleteOptions<T extends Object> extends StatelessWidget { ...@@ -264,6 +275,7 @@ class _AutocompleteOptions<T extends Object> extends StatelessWidget {
final AutocompleteOnSelected<T> onSelected; final AutocompleteOnSelected<T> onSelected;
final Iterable<T> options; final Iterable<T> options;
final double maxOptionsHeight;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -271,10 +283,11 @@ class _AutocompleteOptions<T extends Object> extends StatelessWidget { ...@@ -271,10 +283,11 @@ class _AutocompleteOptions<T extends Object> extends StatelessWidget {
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
child: Material( child: Material(
elevation: 4.0, elevation: 4.0,
child: SizedBox( child: ConstrainedBox(
height: 200.0, constraints: BoxConstraints(maxHeight: maxOptionsHeight),
child: ListView.builder( child: ListView.builder(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: options.length, itemCount: options.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
final T option = options.elementAt(index); final T option = options.elementAt(index);
......
...@@ -254,6 +254,104 @@ void main() { ...@@ -254,6 +254,104 @@ void main() {
expect(find.byKey(optionsKey), findsOneWidget); 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 { testWidgets('initialValue sets initial text field value', (WidgetTester tester) async {
late String lastSelection; late String lastSelection;
await tester.pumpWidget( await tester.pumpWidget(
......
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