94

I am experimenting with Flutter, and currently trying to display an input field and a dropdown in a list view in a dialog box. However, I get the drop-down overflowing the horizontal width of view and causing yellow-gray striped pattern (shown below)

enter image description here Overflow of DropdownButton widget in ListView

The code is:

    class DataInput extends StatefulWidget {

      @override
      State createState() => new DataInputState("");
    }


    enum DismissDialogAction {
      cancel,
      discard,
      save,
    }

    class DataInputState extends State<DataInput> {
      final String _data;
      static const types = const <Map<String, String>>[
        const {
          "id": "103",
          "desc": "0001 - lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum"
        },
        const {
          "id": "804",
          "desc": "0002 - lorem ipsum lorem ipsum"
        },
      ];

      DataInputState(this._data);

      @override
      Widget build(BuildContext context) {
        final ThemeData theme = Theme.of(context);
        return new Scaffold(
          appBar: new AppBar(
            title: const Text("Details"),
            actions: <Widget>[
              new FlatButton(
                  onPressed: () => Navigator.pop(context, DismissDialogAction.save),
                  child: new Row(
                    children: <Widget>[
                      new Icon(Icons.save, color: Colors.white,),
                      new Text(
                          "Save",
                          style: theme.textTheme.body1.copyWith(
                            color: Colors.white,)
                      )
                    ],
                  )
              ),
            ],
          ),
          body: new ListView(
            shrinkWrap: true,
            children: <Widget>[
              new Text("Set Label"),
              new TextField(
                autocorrect: false,
              ),
              new Text("Select Type"),
              new Container(
                width: new FractionColumnWidth(0.5).value,
                child: new DropdownButton(
                    items: types.map((m) =>
                    new DropdownMenuItem(
                        key: new Key(m["id"]),
                        child: new Text(m["desc"]))
                    ).toList(growable: false),
                    onChanged: null
                ),
              ),
            ],
          ),
        );
      }
    }

Error:

    ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
    The following message was thrown during layout:
    A horizontal RenderFlex overflowed by 433 pixels.

    The edge of the RenderFlex that is overflowing has been marked in the rendering with a yellow and
    black striped pattern. This is usually caused by the contents being too big for the RenderFlex.
    RenderFlex to fit within the available space instead of being sized to their natural size.
    This is considered an error condition because it indicates that there is content that cannot be
    seen. If the content is legitimately bigger than the available space, consider clipping it with a
    RectClip widget before putting it in the flex, or using a scrollable container rather than a Flex,
    for example using ListView.
    The specific RenderFlex in question is:
    RenderFlex#cc264 relayoutBoundary=up12 OVERFLOWING
    creator: Row ← SizedBox ← DefaultTextStyle ← Stack ← Listener ← _GestureSemantics ←
    RawGestureDetector ← GestureDetector ← DropdownButton ← ConstrainedBox ← Container ←
    RepaintBoundary-[<3>] ← ⋯
    direction: horizontal
    mainAxisAlignment: space-between
    mainAxisSize: min
    crossAxisAlignment: center
    textDirection: ltr
    verticalDirection: down

I have tried the following approaches, and they don't work:

  • Wrapping the drop down in a Row, Column, Padding and ClipRect

Can someone help me understand this and show how to fix it?

Update Using FittedBox prevents the overflow, but the text size then shrinks to be un-legible.

1

10 Answers 10

247

The easiest solution is to add the isExpanded property to true in DropdownButton

For example:

DropdownButton(
  isExpanded: true, //Adding this property, does the magic
  items: [
    DropdownMenuItem(
      child: Text(
          "Some large text that needs to be wrapped or ellipsized",
          overflow: TextOverflow.ellipsis),
    ),
    DropdownMenuItem(
      child: Text(
          "This is another large text that needs to be wrapped or ellipsized",
          overflow: TextOverflow.ellipsis),
    ),
    DropdownMenuItem(
      child: Text(
          "And one more large text that needs to be wrapped or ellipsized",
          overflow: TextOverflow.ellipsis),
    )
  ],
  onChanged: (val) {
    //print(val);
  },
),
Sign up to request clarification or add additional context in comments.

5 Comments

If you don't want the selected item to be ellipsized, you can also pair this answer with the selectedItemBuilder field in DropdownButton. Or, you can specify itemHeight to be null, so that it can be larger than kMinInteractiveDimension.
legend, I'd dare to say isExpanded: true should be the default value.
When setting this parameter, you may want to wrap the DropdownButton in an Expanded Widget.
isExpanded: true, This line really did magic, Great solution!! Thanks
Aladin's lamp .
35

I managed to solve the issue by wrapping the child of DropdownMenuItem in a SizedBox and by giving sizedBox a fixed width which will not overflow the UI and still look good.

eg.

                   new DropdownMenuItem<String>(
                      value: value,
                      child:  new SizedBox(
                        width: 200.0,
                        child: new Text('Long text with ${value} ')
                      ),
                    )

5 Comments

This works great. You can also use a ConstrainedBox instead of a SizedBox if you want to be able to set min and max widths instead of having a fixed width.
@Daryl Yes, you can you ConstrainedBox or container (and define constraint)
The sized box will cause your text to wrap to the next line if it exceeds the width dimension. Where as isexpanded will adjust the width of the dropdownitem to the text length.
SizedBox didnt work for me when it was in the same row as an expanded widget. But FittedBox worked for me instead
to enable click on down arrow in flutter of dropdown
32

Try using isExpanded: true,

It will automatically extend the text to new line

DropdownButton(
     isExpanded: true, //Add this property
     items: [
          DropdownMenuItem(
              child: Text("Your Text Here", 
              overflow: TextOverflow.ellipsis),
          ),
}),

Refer below image

There was not enough space to text in a line so continued with next line

enter image description here

3 Comments

@iDecode sorry but I didn't get why you downvoted my answer, I was just posting out a solution that worked for me and is related to this question. If you don't like the solution you can just ignore it right?
I downvoted because this answer is already provided and there's no point in writing the same answer in different words. Hope you get the idea.
I thought "isExpanded" will automatically show the dropdown list. So I'm not sure how or why this works but it does.
16

I think you're running into a legit bug with the DropDownButton itself. There is a Github issue about the problem here: https://github.com/flutter/flutter/issues/9211

If you need an immediate fix, you can actually patch up the DropDownButton yourself! To do so:

  1. Open the dropdown.dart from the Flutter Framework and paste it into your own project as fixed_dropdown.dart.
  2. Delete the DropDownMenuItem class from this file so it does not cause conflicts with your normal Flutter imports
  3. Rename DropDownButton to FixedDropDownButton so it does not conflict with Flutter imports
  4. Navigate to the build method of the _DropdownButtonState. Find the IndexedStack inside a Row. Wrap the IndexedStack with an Expanded widget.

I posted this info on the Github Issue itself, and screenshots of this solution can be found there as well if you want to see the fix in action!

1 Comment

This solution breaks if you wrap it in a Row widget, because Expanded causes infinite width. I fixed that in my code, by wrapping in a stackwidget and providing some padding on right of textview and placcing the arrow down button on right.this works fine for me : github.com/apgapg/Flutter_Pull_Request/blob/master/…
16

None of the above solves this problem properly.

please try FittedBox as documented here

just wrap your DropdownMenuItem's child like this

DropdownMenuItem<MyDropdownContentClass>(
            child: FittedBox(
              child: Text("dropdown item display"),
              fit: BoxFit.contain,
            ),
          );

it will automatically resize the whole widget during paint, which is your Text().

1 Comment

In my case, for a big list of strings, this just shrinks some text widgets.
7

In order for this to work if you are using a row, you have to set both the row child to Expanded, and the DropdownButton isExpanded property:

Row(
    children: <Widget>[
      Expanded(
        child: DropdownButton<String>(
          isExpanded: true, 
          value: _selectedLanguageNative,
          items: list,
          hint: Text(LanguageLocal.getDisplayLanguage(
              Localizations.localeOf(context).languageCode)["name"]),
          onChanged: (String value) {
            print(value);
            setState(() {
              _selectedLanguageNative = value;
            });
          },
        ),
      ),
    ],
  ),

Comments

6

Elaborating on ganapat answer you can set up the list this way:

final dropdownItems = _list
        .map((String item) => new DropdownMenuItem<String>(
              value: item,
              child: new SizedBox(width: 200.0, child: new Text(item)),
            ))
        .toList();

Comments

3

I struggled with this and eventually found a perfectly good solution to the problem that @Dah raises. It is hinted at in the Github issue Look at Sep 18, 2019: to make use of the selectedItemBuilder property of the DropDownButton. There is also a good working example here Flutter Docs. I'm including a segment of my code which simply puts ellipsis in place of long text in the dropdownbutton when it is closed. It does his by making use of the returned Text() widget of the selectedItemBuilder, which allows the overflow property to set the ellipsis:

child: DropdownButton<String>(
        isExpanded: true,
        hint: Text('Select Faculty'),
        value: selectedFaculty,
        underline: Container(
          height: 0,
        ),
        onChanged: (String value) async {
          selectedFaculty = value;
        },
        selectedItemBuilder: (BuildContext context) {
          return dropFaculty.map<Widget>((String text) {
            return Text(
              text,
              overflow: TextOverflow.ellipsis,
            );
          }).toList();
        },
        items: disableKeyFields || selectedInstitution == null
            ? null
            : dropFaculty.map((String faculty) {
                return DropdownMenuItem<String>(
                  value: faculty,
                  child: Text(
                    faculty,
                    style: TextStyle(color: Colors.black),
                  ),
                );
              }).toList(),
      ),

Comments

1

Thanks for brianegan's answer.

After step 3, look at the class _DropdownMenuRouteLayout:

  @override
  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
    // The maximum height of a simple menu should be one or more rows less than
    // the view height. This ensures a tappable area outside of the simple menu
    // with which to dismiss the menu.
    //   -- https://material.io/design/components/menus.html#usage
    final double maxHeight =
        math.max(0.0, constraints.maxHeight - 2 * _kMenuItemHeight);
    // The width of a menu should be at most the view width. This ensures that
    // the menu does not extend past the left and right edges of the screen.
    final double width = math.min(constraints.maxWidth, buttonRect.width);
    return BoxConstraints(
      minWidth: width,
      maxWidth: width,
      minHeight: 0.0,
      maxHeight: maxHeight,
    );
  }

You can implement the 'maxWith' in your own way.

Comments

0

An easy and elegant solution that allows you to put the entire text inside the selection is to use BoxFit in combination with isExpanded set to true like this:

DropdownButton(
  isExpanded: true, //Magic #1
  items: [
    DropdownMenuItem(
      child: FittedBox(fit: BoxFit.scaleDown, //Magic #2
        child: Text(
            "Some large text that needs to be wrapped instead ellipsized"),
      ),
    ),
    // The rest of Items
],

For the FittedBox to work correctly you must ensure that the DropDownButton is wrapped in a container with a certain width that allows the function to know in what measurements it should display the text.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.