Repository navigation
Dropdown menus disappear immediately when combined with text fields #41881
Description
On Android, when you have a DropdownButton on the same page as a TextFormField, and tap the dropdown when the text field has focus, then tapping the dropdown button will cause the dropdown to appear, a metrics change to occur (because the keyboard went away when the text field lost focus), and the dropdown disappears immediately, since the dropdown is coded to disappear with a metrics change, making it impossible to make a selection. Popup menus don't have this issue.
In order to combine properly with text fields, we need to figure out how to prevent them from losing the keyboard when they lose focus, so that the keyboard doesn't bounce up and down, which will fix this problem. And perhaps dropdowns shouldn't go away with a metrics change, but there may be other reasons for that.
Example code that shows this:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String value = 'foo';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Material(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 100.0, horizontal: 10.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextFormField(
decoration: InputDecoration(border: OutlineInputBorder()),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
DropdownButton(
value: value,
items: [
DropdownMenuItem(
value: 'foo',
child: Text('Foo'),
),
DropdownMenuItem(
value: 'bar',
child: Text('Bar'),
),
DropdownMenuItem(
value: 'baz',
child: Text('Baz'),
),
],
onChanged: (String value) {
setState(() {
this.value = value;
});
},
),
],
),
],
),
),
),
);
}
}Focus the text field and try and select something from the dropdown.
cc @HansMuller, who has worked on DropdownButton recently.

Activity
ThinkDigitalSoftware commentedon Oct 3, 2019
Linking #41574 to this as well for reference
sarbagyastha commentedon Oct 3, 2019
@gspencergoog , Dropdown is coded to disappear on orientation change actually and there's no better way to detect orientation change in Flutter currently other than listening to metrics change.
ThinkDigitalSoftware commentedon Oct 3, 2019
What about using MediaQuery?
sarbagyastha commentedon Oct 3, 2019
@ThinkDigitalSoftware orientation provided by MediaQuery is based on window size, it won't detect native orientation of device. Also we need to listen to orientation changes, for which we need used onMetricChanged anyhow.
gspencergoog commentedon Oct 3, 2019
I think the right fix is to do what native Android does: don't drop the keyboard when a text field loses focus to another control.
Much easier said than done, of course. This basically means adding another kind of "focus", since Android allows you to keep typing on the keyboard. As soon as you do, it closes the popup menu and adds the text to the field, so the text field never really lost focus as far as the user (or the field highlight) is concerned. In order for keyboard focus traversal to work, though, the popup items need to be able to take the focus so that hitting tab moves the focus, and enter commits the value for the popup, all without changing the text field, so it's...complicated.
Hans and I will discuss this today and come up with some kind of plan.
ThinkDigitalSoftware commentedon Oct 3, 2019
Appreciate it!
ThinkDigitalSoftware commentedon Oct 3, 2019
So I had to downgrade to the stable channel for a different reason and I replaced the material/dropdown.dart from stable with the one @sarbagyastha edited and the dropdown works perfectly (for me at least) I'm happy with its functionality. Even though it may up functioning differently when you guys are done. Tapping a
DropdownButtondismisses the keyboard AND brings up the dropdown menu in a single tap. When the dropdown is dismissed, nothing else happens. The previous TextEditingField is not refocused and the keyboard does not come up. If this is not how it ends up being, can it at least be an optional parameter, maybe abool returnFocusToPreviousWidget:that defaults to true?gspencergoog commentedon Oct 4, 2019
So, after discussing this with @HansMuller, we decided that the following is what needs to happen:
There are two cases: one where a hardware keyboard is present, and one where it isn't.
Hardware Keyboard Present
When a hardware keyboard is present, the
_DropdownRouteneeds to take the focus when pushed, so that keyboard navigation works (which can only happen from a hardware keyboard anyhow). This is basically what the code does now.Hardware Keyboard Not Present (Software Keyboard)
When a hardware keyboard isn't present, then the
_DropdownRoutedoesn't take the focus when it is pushed, the text field keeps the focus, and the keyboard stays up, so as not to cause a metrics change. In addition, if a key is pressed on the software keyboard (a.k.a. an editing event occurs), then the dropdown will dismiss itself, and the text field will handle the event as normal. Also, the text field will need to decide to not blink its cursor if it is not on the top route, so that it stops blinking when the dropdown is visible, but it doesn't lose its focus highlight.To determine if the
_DropdownRouteshould take the focus, we'll use the existence of non-zeroMediaQueryData.viewInsetsas a proxy for whether the keyboard is visible or not, which we use in other places.This should allow things to work for both the hardware keyboard/desktop case, and for the Android/iOS soft keyboard case.
Work Needed
The work needed to get this fixed is to:
_DropdownRouteto predicate requesting focus for itsFocusScopeon whether or notviewInsetsis non-zero.tewshi commentedon Oct 4, 2019
Exactly my pain
github-actions commentedon Aug 27, 2021
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.