@@ -135,6 +135,7 @@ class DropdownMenu<T> extends StatefulWidget {
135
135
this .controller,
136
136
this .initialSelection,
137
137
this .onSelected,
138
+ this .requestFocusOnTap,
138
139
required this .dropdownMenuEntries,
139
140
});
140
141
@@ -228,6 +229,19 @@ class DropdownMenu<T> extends StatefulWidget {
228
229
/// Defaults to null. If null, only the text field is updated.
229
230
final ValueChanged <T ?>? onSelected;
230
231
232
+ /// Determine if the dropdown button requests focus and the on-screen virtual
233
+ /// keyboard is shown in response to a touch event.
234
+ ///
235
+ /// By default, on mobile platforms, tapping on the text field and opening
236
+ /// the menu will not cause a focus request and the virtual keyboard will not
237
+ /// appear. The default behavior for desktop platforms is for the dropdown to
238
+ /// take the focus.
239
+ ///
240
+ /// Defaults to null. Setting this field to true or false, rather than allowing
241
+ /// the implementation to choose based on the platform, can be useful for
242
+ /// applications that want to override the default behavior.
243
+ final bool ? requestFocusOnTap;
244
+
231
245
/// Descriptions of the menu items in the [DropdownMenu] .
232
246
///
233
247
/// This is a required parameter. It is recommended that at least one [DropdownMenuEntry]
@@ -242,7 +256,6 @@ class DropdownMenu<T> extends StatefulWidget {
242
256
class _DropdownMenuState <T > extends State <DropdownMenu <T >> {
243
257
final GlobalKey _anchorKey = GlobalKey ();
244
258
final GlobalKey _leadingKey = GlobalKey ();
245
- final FocusNode _textFocusNode = FocusNode ();
246
259
final MenuController _controller = MenuController ();
247
260
late final TextEditingController _textEditingController;
248
261
late bool _enableFilter;
@@ -288,6 +301,23 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
288
301
}
289
302
}
290
303
304
+ bool canRequestFocus () {
305
+ if (widget.requestFocusOnTap != null ) {
306
+ return widget.requestFocusOnTap! ;
307
+ }
308
+
309
+ switch (Theme .of (context).platform) {
310
+ case TargetPlatform .iOS:
311
+ case TargetPlatform .android:
312
+ case TargetPlatform .fuchsia:
313
+ return false ;
314
+ case TargetPlatform .macOS:
315
+ case TargetPlatform .linux:
316
+ case TargetPlatform .windows:
317
+ return true ;
318
+ }
319
+ }
320
+
291
321
void refreshLeadingPadding () {
292
322
WidgetsBinding .instance.addPostFrameCallback ((_) {
293
323
setState (() {
@@ -428,7 +458,6 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
428
458
429
459
@override
430
460
void dispose () {
431
- _textEditingController.dispose ();
432
461
super .dispose ();
433
462
}
434
463
@@ -489,13 +518,12 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
489
518
builder: (BuildContext context, MenuController controller, Widget ? child) {
490
519
assert (_initialMenu != null );
491
520
final Widget trailingButton = Padding (
492
- padding: const EdgeInsets .symmetric (horizontal : 4.0 ),
521
+ padding: const EdgeInsets .all ( 4.0 ),
493
522
child: IconButton (
494
523
isSelected: controller.isOpen,
495
524
icon: widget.trailingIcon ?? const Icon (Icons .arrow_drop_down),
496
525
selectedIcon: widget.selectedTrailingIcon ?? const Icon (Icons .arrow_drop_up),
497
526
onPressed: () {
498
- _textFocusNode.requestFocus ();
499
527
handlePressed (controller);
500
528
},
501
529
),
@@ -511,7 +539,9 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
511
539
width: widget.width,
512
540
children: < Widget > [
513
541
TextField (
514
- focusNode: _textFocusNode,
542
+ canRequestFocus: canRequestFocus (),
543
+ enableInteractiveSelection: canRequestFocus (),
544
+ textAlignVertical: TextAlignVertical .center,
515
545
style: effectiveTextStyle,
516
546
controller: _textEditingController,
517
547
onEditingComplete: () {
0 commit comments