Flutter - DropdownButton 溢出
Posted
技术标签:
【中文标题】Flutter - DropdownButton 溢出【英文标题】:Flutter - DropdownButton overflow 【发布时间】:2018-04-12 10:29:04 【问题描述】:我正在尝试使用 Flutter,目前正在尝试在对话框的列表视图中显示输入字段和下拉列表。但是,我得到的下拉菜单会溢出视图的水平宽度并导致黄灰色条纹图案(如下所示)
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
可以防止溢出,但文本大小会缩小到无法辨认。
【问题讨论】:
试试 DropDownButton 的 isExpanded 属性。来源:***.com/a/53213558/2551290 【参考方案1】:我认为您遇到了DropDownButton
本身的合法错误。这里有一个关于这个问题的 Github issue:https://github.com/flutter/flutter/issues/9211
如果您需要立即修复,您实际上可以自己修补 DropDownButton!这样做:
-
从 Flutter Framework 中打开
dropdown.dart
并将其粘贴到您自己的项目中作为 fixed_dropdown.dart
。
从此文件中删除 DropDownMenuItem
类,以免它与您的正常 Flutter 导入冲突
将 DropDownButton
重命名为 FixedDropDownButton
,以免与 Flutter 导入冲突
导航到_DropdownButtonState
的build
方法。在Row
中找到IndexedStack
。用 Expanded
小部件包裹 IndexedStack
。
我在 Github 问题本身上发布了此信息,如果您想查看实际修复,也可以在此处找到此解决方案的屏幕截图!
【讨论】:
如果您将其包装在 Row 小部件中,此解决方案会中断,因为 Expanded 会导致无限宽度。我在我的代码中修复了这个问题,方法是包装在一个堆栈小部件中并在 textview 的右侧提供一些填充并将向下箭头按钮放在右侧。这对我来说很好:github.com/apgapg/Flutter_Pull_Request/blob/master/…【参考方案2】:我设法通过将 DropdownMenuItem 的子项包装在 SizedBox 中并为 sizedBox 提供一个不会溢出 UI 并且看起来还不错的固定宽度来解决这个问题。
例如。
new DropdownMenuItem<String>(
value: value,
child: new SizedBox(
width: 200.0,
child: new Text('Long text with $value ')
),
)
【讨论】:
这很好用。如果您希望能够设置最小和最大宽度而不是固定宽度,也可以使用 ConstrainedBox 而不是 SizedBox。 @Daryl 是的,你可以使用 ConstrainedBox 或容器(并定义约束) 如果超出宽度尺寸,大小框将导致您的文本换行到下一行。其中 isexpanded 会将下拉项的宽度调整为文本长度。 SizedBox 在与展开的小部件位于同一行时对我不起作用。但 FittedBox 对我有用 启用在下拉菜单中点击向下箭头【参考方案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】:最简单的解决方案是在DropdownButton
中将isExpanded
属性添加到true
例如:
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);
),
【讨论】:
如果您不希望所选项目被椭圆化,您也可以将此答案与 DropdownButton 中的selectedItemBuilder
字段配对。或者,您可以将itemHeight
指定为null,使其大于kMinInteractiveDimension。
传奇,我敢说 isExpanded: true 应该是默认值。【参考方案5】:
以上方法都不能很好地解决这个问题。
请以 documented here 的身份尝试 FittedBox
像这样包裹你的 DropdownMenuItem 的孩子
DropdownMenuItem<MyDropdownContentClass>(
child: FittedBox(
child: Text("dropdown item display"),
fit: BoxFit.contain,
),
);
它会在绘制期间自动调整整个小部件的大小,即您的 Text()。
【讨论】:
就我而言,对于一大串字符串,这只是缩小了一些文本小部件。【参考方案6】:感谢 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”。
【讨论】:
【参考方案7】:如果您使用的是行,为了使此功能起作用,您必须将行子级设置为 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;
);
,
),
),
],
),
【讨论】:
【参考方案8】:我为此苦苦挣扎,最终为@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(),
),
【讨论】:
【参考方案9】:尝试使用isExpanded: true,
它会自动将文本扩展到新行
DropdownButton(
isExpanded: true, //Add this property
items: [
DropdownMenuItem(
child: Text("Your Text Here",
overflow: TextOverflow.ellipsis),
),
),
参考下图
一行文字空间不足,请继续下一行
【讨论】:
几个月前有人提到过here。请不要为了发布而发布答案。 -1 来自我! @iDecode 抱歉,但我不明白您为什么不赞成我的回答,我只是发布了一个对我有用且与此问题相关的解决方案。如果您不喜欢该解决方案,您可以忽略它对吗? 我投了反对票,因为这个答案已经提供了,用不同的词写相同的答案是没有意义的。希望你能明白。以上是关于Flutter - DropdownButton 溢出的主要内容,如果未能解决你的问题,请参考以下文章
Dart / flutter:DropdownButton在值更改时导致异常
Flutter - 如何在小部件测试中选择 DropdownButton 项
Flutter GetBuilder Dependent DropDownButton - 即使值已被重置,也应该只有一项具有 [DropdownButton] 的值
如何像 Flutter 中的 Spinner 一样在 DropdownButton 下方打开 DropDown 对话框?