Skip to content

Dropdown menus disappear immediately when combined with text fields #41881

Closed

Description

@gspencergoog

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.

dropdown_issue

cc @HansMuller, who has worked on DropdownButton recently.

Activity

  1. added
    c: regressionIt was better in the past than it is now
    platform-androidAndroid applications specifically
    frameworkflutter/packages/flutter repository. See also f: labels.
    p: material_uimaterial_ui package in flutter/packages
    on Oct 3, 2019
  2. ThinkDigitalSoftware commented on Oct 3, 2019

    @ThinkDigitalSoftware
    Contributor

    Linking #41574 to this as well for reference

  3. sarbagyastha commented on Oct 3, 2019

    @sarbagyastha
    Contributor

    @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.

  4. ThinkDigitalSoftware commented on Oct 3, 2019

    @ThinkDigitalSoftware
    Contributor

    What about using MediaQuery?

  5. sarbagyastha commented on Oct 3, 2019

    @sarbagyastha
    Contributor

    @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.

  6. gspencergoog commented on Oct 3, 2019

    @gspencergoog
    ContributorAuthor

    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.

  7. ThinkDigitalSoftware commented on Oct 3, 2019

    @ThinkDigitalSoftware
    Contributor

    Appreciate it!

  8. ThinkDigitalSoftware commented on Oct 3, 2019

    @ThinkDigitalSoftware
    Contributor

    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 DropdownButton dismisses 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?

  9. gspencergoog commented on Oct 4, 2019

    @gspencergoog
    ContributorAuthor

    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 _DropdownRoute needs 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 _DropdownRoute doesn'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 _DropdownRoute should take the focus, we'll use the existence of non-zero MediaQueryData.viewInsets as 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:

    • Wire up a notification for text connection editing events to the dropdown menu so it can dismiss itself if the keyboard is showing and one happens.
    • Modify the text field to not blink the cursor if another route is on top of it.
    • Modify the _DropdownRoute to predicate requesting focus for its FocusScope on whether or not viewInsets is non-zero.
  10. tewshi commented on Oct 4, 2019

    @tewshi

    Exactly my pain

  11. self-assigned this
    on Oct 10, 2019
  12. github-actions commented on Aug 27, 2021

    @github-actions

    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 -v and a minimal reproduction of the issue.

  13. locked as resolved and limited conversation to collaborators on Aug 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

c: regressionIt was better in the past than it is nowframeworkflutter/packages/flutter repository. See also f: labels.p: material_uimaterial_ui package in flutter/packagesplatform-androidAndroid applications specifically

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions