mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[web] Arrow keys change selected item in dropdown (#76656)
This commit is contained in:
parent
f7823d58da
commit
f5343f4f23
@ -161,7 +161,10 @@ class _DropdownMenuItemButtonState<T> extends State<_DropdownMenuItemButton<T>>
|
||||
}
|
||||
|
||||
static final Map<LogicalKeySet, Intent> _webShortcuts =<LogicalKeySet, Intent>{
|
||||
LogicalKeySet(LogicalKeyboardKey.enter): const ActivateIntent(),
|
||||
// On the web, up/down don't change focus, *except* in a <select>
|
||||
// element, which is what a dropdown emulates.
|
||||
LogicalKeySet(LogicalKeyboardKey.arrowDown): const DirectionalFocusIntent(TraversalDirection.down),
|
||||
LogicalKeySet(LogicalKeyboardKey.arrowUp): const DirectionalFocusIntent(TraversalDirection.up),
|
||||
};
|
||||
|
||||
@override
|
||||
@ -188,8 +191,6 @@ class _DropdownMenuItemButtonState<T> extends State<_DropdownMenuItemButton<T>>
|
||||
),
|
||||
);
|
||||
if (kIsWeb) {
|
||||
// On the web, enter doesn't select things, *except* in a <select>
|
||||
// element, which is what a dropdown emulates.
|
||||
child = Shortcuts(
|
||||
shortcuts: _webShortcuts,
|
||||
child: child,
|
||||
|
||||
@ -2601,7 +2601,7 @@ void main() {
|
||||
final Element element = tester.element(find.byKey(const ValueKey<String>('two')).last);
|
||||
final FocusNode node = Focus.of(element);
|
||||
expect(node.hasFocus, isTrue);
|
||||
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/55320
|
||||
});
|
||||
|
||||
testWidgets('Selected element is correctly focused with dropdown that more items than fit on the screen', (WidgetTester tester) async {
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton');
|
||||
@ -2664,7 +2664,7 @@ void main() {
|
||||
final Element element = tester.element(find.byKey(const ValueKey<int>(42)).last);
|
||||
final FocusNode node = Focus.of(element);
|
||||
expect(node.hasFocus, isTrue);
|
||||
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/55320
|
||||
});
|
||||
|
||||
testWidgets("Having a focused element doesn't interrupt scroll when flung by touch", (WidgetTester tester) async {
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton');
|
||||
@ -2738,7 +2738,66 @@ void main() {
|
||||
// Scrolling to the top again has removed the one the focus was on from the
|
||||
// tree, causing it to lose focus.
|
||||
expect(Focus.of(tester.element(find.byKey(const ValueKey<int>(91)).last)).hasPrimaryFocus, isFalse);
|
||||
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/55320
|
||||
});
|
||||
|
||||
testWidgets('DropdownButton changes selected item with arrow keys', (WidgetTester tester) async {
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton');
|
||||
String? value = 'one';
|
||||
|
||||
Widget buildFrame() {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return DropdownButton<String>(
|
||||
focusNode: focusNode,
|
||||
autofocus: true,
|
||||
onChanged: (String? newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
},
|
||||
value: value,
|
||||
itemHeight: null,
|
||||
items: menuItems.map<DropdownMenuItem<String>>((String item) {
|
||||
return DropdownMenuItem<String>(
|
||||
key: ValueKey<String>(item),
|
||||
value: item,
|
||||
child: Text(item, key: ValueKey<String>(item + 'Text')),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildFrame());
|
||||
await tester.pump(); // Pump a frame for autofocus to take effect.
|
||||
expect(focusNode.hasPrimaryFocus, isTrue);
|
||||
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.enter);
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(seconds: 1)); // finish the menu animation
|
||||
expect(value, equals('one'));
|
||||
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); // Focus 'two'.
|
||||
await tester.pump();
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); // Focus 'three'.
|
||||
await tester.pump();
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp); // Back to 'two'.
|
||||
await tester.pump();
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.enter); // Select 'two'.
|
||||
await tester.pump();
|
||||
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(seconds: 1)); // finish the menu animation
|
||||
|
||||
expect(value, equals('two'));
|
||||
});
|
||||
|
||||
testWidgets('DropdownButton onTap callback is called when defined', (WidgetTester tester) async {
|
||||
int dropdownButtonTapCounter = 0;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user