Skip to content

Commit b5847d3

Browse files
Delay DropdownMenu filtering until text input (#152368)
fixes flutter/flutter#152055 Disabling filtering in `DropdownMenu` at start and after a selection has been made, and re-enable it (if `widget.enableFilter` is true) after text input. This way it doesn't hide all other options when there is an existing selection. Note: currently this may crush due to issue flutter/flutter#151878 . Which is not directly related to this PR
1 parent 6ef1156 commit b5847d3

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

packages/flutter/lib/src/material/dropdown_menu.dart

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
488488
final GlobalKey _leadingKey = GlobalKey();
489489
late List<GlobalKey> buttonItemKeys;
490490
final MenuController _controller = MenuController();
491-
late bool _enableFilter;
491+
bool _enableFilter = false;
492492
late List<DropdownMenuEntry<T>> filteredEntries;
493493
List<Widget>? _initialMenu;
494494
int? currentHighlight;
@@ -504,7 +504,6 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
504504
} else {
505505
_localTextEditingController = TextEditingController();
506506
}
507-
_enableFilter = widget.enableFilter;
508507
filteredEntries = widget.dropdownMenuEntries;
509508
buttonItemKeys = List<GlobalKey>.generate(filteredEntries.length, (int index) => GlobalKey());
510509
_menuHasEnabledItem = filteredEntries.any((DropdownMenuEntry<T> entry) => entry.enabled);
@@ -537,6 +536,11 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
537536
}
538537
_localTextEditingController = widget.controller ?? TextEditingController();
539538
}
539+
if (oldWidget.enableFilter != widget.enableFilter) {
540+
if (!widget.enableFilter) {
541+
_enableFilter = false;
542+
}
543+
}
540544
if (oldWidget.enableSearch != widget.enableSearch) {
541545
if (!widget.enableSearch) {
542546
currentHighlight = null;
@@ -676,6 +680,7 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
676680
);
677681
currentHighlight = widget.enableSearch ? i : null;
678682
widget.onSelected?.call(entry.value);
683+
_enableFilter = false;
679684
}
680685
: null,
681686
requestFocusOnHover: false,
@@ -748,6 +753,8 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
748753
if (_enableFilter) {
749754
filteredEntries = widget.filterCallback?.call(filteredEntries, _localTextEditingController!.text)
750755
?? filter(widget.dropdownMenuEntries, _localTextEditingController!);
756+
} else {
757+
filteredEntries = widget.dropdownMenuEntries;
751758
}
752759

753760
if (widget.enableSearch) {

packages/flutter/test/material/dropdown_menu_test.dart

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2524,6 +2524,49 @@ void main() {
25242524

25252525
expect(menuAnchor.alignmentOffset, alignmentOffset);
25262526
});
2527+
2528+
testWidgets('DropdownMenu filter is disabled until text input', (WidgetTester tester) async{
2529+
await tester.pumpWidget(MaterialApp(
2530+
home: Scaffold(
2531+
body: DropdownMenu<TestMenu>(
2532+
requestFocusOnTap: true,
2533+
enableFilter: true,
2534+
initialSelection: menuChildren[0].value,
2535+
dropdownMenuEntries: menuChildren,
2536+
),
2537+
),
2538+
));
2539+
2540+
await tester.tap(find.byType(DropdownMenu<TestMenu>));
2541+
await tester.pumpAndSettle();
2542+
2543+
// All entries should be available, and two buttons should be found for each entry.
2544+
// One is layout for the _DropdownMenuBody, the other one is the real button item in the menu.
2545+
for (final TestMenu menu in TestMenu.values) {
2546+
expect(find.widgetWithText(MenuItemButton, menu.label), findsNWidgets(2));
2547+
}
2548+
2549+
// Text input would enable the filter.
2550+
await tester.enterText(find.byType(TextField).first, 'Menu 1');
2551+
await tester.pumpAndSettle();
2552+
for (final TestMenu menu in TestMenu.values) {
2553+
// 'Menu 1' should be 2, other items should only find one.
2554+
if (menu.label == TestMenu.mainMenu1.label) {
2555+
expect(find.widgetWithText(MenuItemButton, menu.label), findsNWidgets(2));
2556+
} else {
2557+
expect(find.widgetWithText(MenuItemButton, menu.label), findsOneWidget);
2558+
}
2559+
}
2560+
2561+
// Selecting an item would disable filter again.
2562+
await tester.tap(find.widgetWithText(MenuItemButton, 'Menu 1').last);
2563+
await tester.pumpAndSettle();
2564+
await tester.tap(find.byType(DropdownMenu<TestMenu>));
2565+
await tester.pumpAndSettle();
2566+
for (final TestMenu menu in TestMenu.values) {
2567+
expect(find.widgetWithText(MenuItemButton, menu.label), findsNWidgets(2));
2568+
}
2569+
});
25272570
}
25282571

25292572
enum TestMenu {

0 commit comments

Comments
 (0)