Flutter如何构建内置可滚动ElevatedButton列表的自定义Row组件
报错原因
- 第一类
Horizontal viewport was given unbounded width是因为横向滚动的ListView外层没有明确的宽度约束,Row的子元素默认会尽可能占满水平空间,横向列表没有边界就触发布局溢出。 - 第二类
RenderBox was not laid out是因为你在横向ListView的子元素里加了Expanded,滚动列表的子元素在滚动方向上没有上限,Expanded无法计算可占用的空间,导致布局无法生成尺寸。
修复步骤
- 把原来包裹横向
ListView的无尺寸SizedBox替换为Expanded,让横向按钮区域占用Row内TextField和删除按钮之外的剩余可用宽度,获得明确的宽度约束。 - 删除横向
ListView内部所有ElevatedButton外层的Expanded,按钮会自动适配自身内容宽度,不会触发布局计算冲突。 - 如果需要限制横向按钮区域的最大宽度,可以在
Expanded内部嵌套ConstrainedBox设置maxWidth参数即可。
修复后核心代码示例
if(widget == "selection"){ return Row( children: [ Expanded( child: TextField( onChanged: (val){ onUpdate(key, val); }, keyboardType: type, decoration: InputDecoration( labelText: key.toString(), labelStyle: TextStyle( fontSize: 14.0, ), hintStyle: TextStyle( color: Colors.grey, fontSize: 10.0, ), ), style: TextStyle(fontSize: 14.0), ), ), SizedBox(width: 8.0,), // 替换原有SizedBox为Expanded提供宽度约束 Expanded( // 可选:添加ConstrainedBox限制最大宽度 // child: ConstrainedBox( // constraints: BoxConstraints(maxWidth: 250), child: ListView( scrollDirection: Axis.horizontal, children: [ // 移除所有按钮外层的Expanded ElevatedButton( onPressed: (){}, child: Text("HELLO"), ), SizedBox(width: 4), ElevatedButton( onPressed: (){}, child: Text("HELLO"), ), SizedBox(width: 4), ElevatedButton( onPressed: (){}, child: Text("HELLO"), ), SizedBox(width: 4), // 新增按钮入口 TextButton( onPressed: (){ // 在这里实现新增按钮的逻辑,把按钮项存入对应状态列表动态渲染即可 }, child: Icon(Icons.add), ) ], ), // ), ), SizedBox(width: 4.0,), TextButton( onPressed: (){ setState(() { Map<String, dynamic> tempMap = {}; for(final element in widgetList) { if(element["id"] == key){ tempMap = element; break; } } widgetList.remove(tempMap); for(final element in customTextValuesList) { if(element["id"] == key){ tempMap = element; break; } } customTextValuesList.remove(tempMap); }); }, child: Icon(Icons.close, color: Colors.red,), ), ], ); }
动态新增按钮可以通过状态管理实现:把每个selection类型行的按钮列表存在和行key绑定的数组中,动态遍历数组渲染按钮,点击+按钮时给对应数组新增一项即可。
内容的提问来源于stack exchange,提问作者Firenze
相关产品推荐
相关产品推荐

