Flutter渲染DropDownMenu与ListView报RenderBox未布局错误如何修复
报错原因
报错核心是Column和ListView的布局约束冲突:
Column作为垂直线性布局,会向子组件传递无界的垂直方向高度约束,允许子组件在垂直方向无限延伸ListView是垂直滚动的视口组件,默认行为是在垂直方向尽可能撑满所有可用空间
当这两个组件嵌套时,ListView拿到无界高度约束,无法计算自身实际需要的渲染高度,就会触发Vertical viewport was given unbounded height控制台报错,连带抛出RenderBox was not laid out的布局异常,DropdownButton本身不是报错诱因。
修复方案
根据业务场景二选一即可:
方案1:列表自适应内容高度(适合列表数据量小的场景)
给ListView.builder添加对应属性:
shrinkWrap: true:让ListView根据子组件总高度设置自身高度,不再尝试撑满可用垂直空间physics: const NeverScrollableScrollPhysics():禁用ListView自身的滚动响应,把滚动行为交给外层父组件(如果整个页面需要统一滚动时添加,不需要可以省略)
对应修改后的代码片段:
ListView.builder( shrinkWrap: true, // 不需要列表自身滚动时加下面这行 physics: const NeverScrollableScrollPhysics(), itemCount: _lessonsList.length, itemBuilder: (BuildContext context, int index) { final lesson = _lessonsList[index]; bool? checkboxValue = _checkboxValues[index]; return CheckboxListTile( title: Text(lesson.lessonName ?? ''), controlAffinity: ListTileControlAffinity.leading, contentPadding: EdgeInsets.zero, value: checkboxValue, onChanged: (bool? value) => _changeCheckboxState(value, index, lesson), ); }, )
注意:
shrinkWrap: true会一次性渲染列表所有子项计算总高度,列表数据量大时会有明显性能问题,不要在长列表场景使用。
方案2:列表占满Column剩余高度(推荐,长列表性能更好)
用Expanded组件包裹ListView.builder,让ListView自动占满Column除了DropdownButton之外的剩余垂直空间,此时ListView可以正常拿到明确的高度约束,也能保留内置的懒加载能力,长列表场景无性能问题。
对应修改后的完整可运行代码:
BlocConsumer<StudentBloc, StudentState>( listener: _listener, builder: (context, state) { return Column( children: [ DropdownButton<Group>( value: _group, icon: const Icon(Icons.arrow_downward), elevation: 16, onChanged: _changeDropdownMenuState, items: _groupsList.map<DropdownMenuItem<Group>>( (Group value) { return DropdownMenuItem<Group>( value: value, child: Text(value.groupName ?? ''), ); }, ).toList(), ), // 用Expanded包裹ListView解决约束冲突 Expanded( child: ListView.builder( itemCount: _lessonsList.length, itemBuilder: (BuildContext context, int index) { final lesson = _lessonsList[index]; bool? checkboxValue = _checkboxValues[index]; return CheckboxListTile( title: Text(lesson.lessonName ?? ''), controlAffinity: ListTileControlAffinity.leading, contentPadding: EdgeInsets.zero, value: checkboxValue, onChanged: (bool? value) => _changeCheckboxState(value, index, lesson), ); }, ), ), ], ); }, )
内容的提问来源于stack exchange,提问作者userName
相关产品推荐
相关产品推荐

