Flutter - ListView中的DropdownButton溢出

时间:2017-10-31 09:47:34

标签: dart flutter

我正在尝试Flutter,目前正尝试在对话框的列表视图中显示输入字段和下拉列表。但是,我得到的下拉式溢出了视图的水平宽度并导致黄灰色条纹图案(如下所示)

enter image description here ListView

中的DropdownButton小部件溢出

代码是:

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

错误:

    ══╡ 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

我尝试了以下方法,但它们不起作用:

  • 在行,列,填充和ClipRect中包装下拉列表

有人可以帮助我理解这一点,并说明如何解决它吗?

更新 使用FittedBox可以防止溢出,但文本大小会缩小到不可读的范围。

9 个答案:

答案 0 :(得分:11)

我设法通过将DropdownMenuItem的子项包装在SizedBox中并通过给sizeBox一个固定宽度来解决问题,该宽度不会溢出UI并且看起来仍然很好。

例如。

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

答案 1 :(得分:10)

我认为您已经遇到DropDownButton本身的合法错误。这里有一个关于这个问题的Github问题:https://github.com/flutter/flutter/issues/9211

如果您需要立即修复,您实际上可以自己修补DropDownButton!为此:

  1. 从Flutter Framework中打开dropdown.dart,然后将其粘贴到您自己的项目fixed_dropdown.dart中。
  2. 从此文件中删除DropDownMenuItem类,以免与正常的Flutter导入冲突
  3. DropDownButton重命名为FixedDropDownButton,以便与Flutter导入不冲突
  4. 导航至build的{​​{1}}方法。在_DropdownButtonState内找到IndexedStack。使用Row小部件包裹IndexedStack
  5. 我在Github问题上发布了这个信息,如果你想看到修复程序的运行,也可以找到这个解决方案的截图!

答案 2 :(得分:10)

最简单的解决方案是将isExpanded属性添加到true中的DropdownButton

例如:

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"),
                ),
                new DropdownMenuItem(
                  child: Text("This is another large text that needs to be wrapped or ellipsized"),
                ),
                new DropdownMenuItem(
                  child: Text("And one more large text that needs to be wrapped or ellipsized"),
                )
              ],
              onChanged: (val) {
                //print(val);
              }),

答案 3 :(得分:3)

详细说明ganapat回答你可以这样设置列表:

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

答案 4 :(得分:3)

为使此功能在您使用一行时起作用,必须将行子级设置为 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;
            });
          },
        ),
      ),
    ],
  ),

答案 5 :(得分:1)

我为此苦苦挣扎,最终找到了@Dah提出的问题的完美解决方案。 Github问题Look at Sep 18, 2019中暗示了这一点:利用DropDownButton的selectedItemBuilder属性。 Flutter Docs这里也有一个很好的示例。 我包括了一段代码,当关闭时,仅在下拉按钮中用省略号代替长文本。它是通过使用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(),
      ),

答案 6 :(得分:0)

以上方法均不能正确解决此问题。

请尝试将FittedBox设置为documented here

像这样包裹您的DropdownMenuItem的孩子

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

它将在绘制过程中自动调整整个小部件的大小,这就是您的Text()。

答案 7 :(得分:0)

感谢Brianegan的回答。

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

您可以用自己的方式实现'maxWith'。

答案 8 :(得分:0)

尝试使用isExpanded: true,

它将自动将文本扩展到新行

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

请参考下图

一行中没有足够的文本空间,因此继续下一行

enter image description here