Fix DropdownMenu focus traversal (#153931)

## Description

This PR fixes `DropdownMenu` focus traversal.

Before this PR, if a `DropdownMenu` contains several items, the 'tab' key had to be pressed many times before the focus move to the inner text field.

This fix is based on https://github.com/flutter/flutter/issues/131120#issuecomment-1654233358.

## Related Issue

Fixes https://github.com/flutter/flutter/issues/131120.

## Tests

Adds 1 test.
This commit is contained in:
Bruno Leroux 2024-08-23 09:57:08 +02:00 committed by GitHub
parent b6c14d783a
commit 402ed6c503
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 41 additions and 3 deletions

View File

@ -890,7 +890,7 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
width: widget.width,
children: <Widget>[
textField,
..._initialMenu!,
..._initialMenu!.map((Widget item) => ExcludeFocus(excluding: !controller.isOpen, child: item)),
trailingButton,
leadingButton,
],

View File

@ -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: <Widget>[
DropdownMenu<TestMenu>(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(