diff --git a/packages/flutter/lib/src/material/dropdown_menu.dart b/packages/flutter/lib/src/material/dropdown_menu.dart index a6cb62cff4f..d6861bea370 100644 --- a/packages/flutter/lib/src/material/dropdown_menu.dart +++ b/packages/flutter/lib/src/material/dropdown_menu.dart @@ -670,7 +670,7 @@ class _DropdownMenuState extends State> { ) : effectiveStyle; - final Widget menuItemButton = MenuItemButton( + final Widget menuItemButton = MenuItemButton( key: enableScrollToHighlight ? buttonItemKeys[i] : null, style: effectiveStyle, leadingIcon: entry.leadingIcon, @@ -890,7 +890,7 @@ class _DropdownMenuState extends State> { width: widget.width, children: [ textField, - ..._initialMenu!, + ..._initialMenu!.map((Widget item) => ExcludeFocus(excluding: !controller.isOpen, child: item)), trailingButton, leadingButton, ], diff --git a/packages/flutter/test/material/dropdown_menu_test.dart b/packages/flutter/test/material/dropdown_menu_test.dart index b1527427a2f..6642f8881ac 100644 --- a/packages/flutter/test/material/dropdown_menu_test.dart +++ b/packages/flutter/test/material/dropdown_menu_test.dart @@ -2427,6 +2427,44 @@ void main() { expect(box, paints..rrect(color: theme.colorScheme.primary)); }); + // Regression test for https://github.com/flutter/flutter/issues/131120. + testWidgets('Focus traversal ignores non visible entries', (WidgetTester tester) async { + final FocusNode buttonFocusNode = FocusNode(); + addTearDown(buttonFocusNode.dispose); + + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: Column( + children: [ + DropdownMenu(dropdownMenuEntries: menuChildren), + ElevatedButton( + focusNode: buttonFocusNode, + onPressed: () {}, + child: const Text('Button'), + ) + ], + ), + ), + )); + + // Move the focus to the text field. + primaryFocus!.nextFocus(); + await tester.pump(); + final Element textField = tester.element(find.byType(TextField)); + expect(Focus.of(textField).hasFocus, isTrue); + + // Move the focus to the dropdown trailing icon. + primaryFocus!.nextFocus(); + await tester.pump(); + final Element iconButton = tester.firstElement(find.byIcon(Icons.arrow_drop_down)); + expect(Focus.of(iconButton).hasFocus, isTrue); + + // Move the focus to the elevated button. + primaryFocus!.nextFocus(); + await tester.pump(); + expect(buttonFocusNode.hasFocus, isTrue); + }); + testWidgets('DropdownMenu honors inputFormatters', (WidgetTester tester) async { int called = 0; final TextInputFormatter formatter = TextInputFormatter.withFunction( @@ -2562,7 +2600,7 @@ void main() { DropdownMenu( dropdownMenuEntries: >[], ), - DropdownMenu( + DropdownMenu( textAlign: TextAlign.center, dropdownMenuEntries: >[], ),