简体   繁体   English

Flutter - DropdownButton 溢出

[英]Flutter - DropdownButton overflow

I am experimenting with Flutter, and currently trying to display an input field and a dropdown in a list view in a dialog box.我正在试验 Flutter,目前正在尝试在对话框的列表视图中显示输入字段和下拉列表。 However, I get the drop-down overflowing the horizontal width of view and causing yellow-gray striped pattern (shown below)但是,我得到下拉溢出视图的水平宽度并导致黄灰色条纹图案(如下所示)

在此处输入图片说明 Overflow of DropdownButton widget in ListView ListView 中 DropdownButton 小部件的溢出

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将下拉框包裹在行、列、填充和 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.使用FittedBox更新可以防止溢出,但文本大小会缩小到难以辨认。

The easiest solution is to add the isExpanded property to true in DropdownButton最简单的解决方案是在DropdownButton中将isExpanded属性添加为true

For example:例如:

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

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.我设法通过将 DropdownMenuItem 的子项包装在 SizedBox 中并给 sizedBox 一个固定宽度来解决这个问题,该宽度不会溢出 UI 并且仍然看起来不错。

eg.例如。

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

I think you're running into a legit bug with the DropDownButton itself.我认为您遇到了DropDownButton本身的合法错误。 There is a Github issue about the problem here: https://github.com/flutter/flutter/issues/9211这里有一个关于这个问题的 Github 问题: https : //github.com/flutter/flutter/issues/9211

If you need an immediate fix, you can actually patch up the DropDownButton yourself!如果您需要立即修复,您实际上可以自己修补 DropDownButton! To do so:这样做:

  1. Open the dropdown.dart from the Flutter Framework and paste it into your own project as fixed_dropdown.dart .从 Flutter 框架中打开dropdown.dart并将其作为fixed_dropdown.dart粘贴到您自己的项目中。
  2. Delete the DropDownMenuItem class from this file so it does not cause conflicts with your normal Flutter imports从此文件中删除DropDownMenuItem类,以免与正常的 Flutter 导入发生冲突
  3. Rename DropDownButton to FixedDropDownButton so it does not conflict with Flutter importsDropDownButton重命名为FixedDropDownButton以免与 Flutter 导入冲突
  4. Navigate to the build method of the _DropdownButtonState .导航到_DropdownButtonStatebuild方法。 Find the IndexedStack inside a Row .Row找到IndexedStack Wrap the IndexedStack with an Expanded widget.使用Expanded小部件包装IndexedStack

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!我在 Github 问题本身上发布了此信息,如果您想查看修复程序,也可以在那里找到此解决方案的屏幕截图!

Try using isExpanded: true,尝试使用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一行文字没有足够的空间,所以继续下一行

在此处输入图片说明

None of the above solves this problem properly.以上都没有正确解决这个问题。

please try FittedBox as documented here请尝试此处记录的FittedBox

just wrap your DropdownMenuItem's child like this就像这样包裹你的 DropdownMenuItem 的孩子

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().它会在绘制期间自动调整整个小部件的大小,即您的 Text()。

Elaborating on ganapat answer you can set up the list this way:详细说明 ganapat 答案,您可以通过以下方式设置列表:

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

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:如果您正在使用一行,为了使其工作,您必须将行子项设置为Expanded和 DropdownButton isExpanded属性:

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;
            });
          },
        ),
      ),
    ],
  ),

Thanks for brianegan's answer.感谢 brianegan 的回答。

After step 3, look at the class _DropdownMenuRouteLayout:第3步之后,查看类_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.您可以以自己的方式实现“maxWith”。

I struggled with this and eventually found a perfectly good solution to the problem that @Dah raises.我为此苦苦挣扎,最终为@Dah 提出的问题找到了一个完美的解决方案。 It is hinted at in the Github issue Look at Sep 18, 2019 : to make use of the selectedItemBuilder property of the DropDownButton.在 Github 问题Look at Sep 18, 2019 中暗示:利用 DropDownButton 的 selectedItemBuilder 属性。 There is also a good working example here Flutter Docs .这里还有一个很好的工作示例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:它通过使用 selectedItemBuilder 返回的 Text() 小部件来实现,它允许溢出属性设置省略号:

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(),
      ),

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM