Flutter中嵌套Column与ListView.builder如何避免布局重叠
Flutter嵌套ListView布局底部重叠问题解决
问题说明
我的Flutter代码出现底部布局重叠的问题,代码采用嵌套结构:在Column内包含ListView.builder,且该ListView.builder的子项中又嵌套了另一个ListView.builder。
布局重叠效果

原代码
body: SafeArea( child: SingleChildScrollView( child: Container( padding: EdgeInsets.fromLTRB( (_deviceWidth! * 0.05), 10, (_deviceWidth! * 0.05), 0), child: Column( children: [ _titleText(), ListView.builder( itemCount: _exercises.length, physics: NeverScrollableScrollPhysics(), shrinkWrap: true, itemBuilder: (BuildContext context, int _index) { return Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.max, children: [ if (_exercises[_index].sets.isNotEmpty) Text(_exercises[_index].name), ListView.builder( physics: NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: _exercises[_index].sets.length, itemBuilder: (BuildContext _context, int _index2) { return ListTile( leading: Text("Sæt " + (_index2 + 1).toString()), trailing: Text( _exercises[_index].sets[_index2].reps.toString() + " reps"), tileColor: Colors.grey, onTap: () { _repsPopUp(_index, _index2); }, title: Text(_exercises[_index].name), onLongPress: () { setState(() { _exercises[_index].sets.removeAt(_index2); if (_exercises[_index].sets.isEmpty) { _exercises.removeAt(_index); } }); }, ); }), ], ); }), ], ), ), ), ),
解决方法
问题出在内层ListView.builder返回的Column上,它设置了mainAxisSize: MainAxisSize.max,这会让Column尝试占满父容器的最大高度,而外层的ListView已经启用了shrinkWrap: true,需要根据子项的实际高度来计算自身高度,两者冲突导致布局重叠。
方案一:修改内层Column的mainAxisSize
只需将内层Column的mainAxisSize改为MainAxisSize.min,让Column仅包裹自身内容的高度,就能让嵌套的ListView正确计算高度,解决重叠问题:
return Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, // 修改此处 children: [ // ... 原有子项内容 ], );
方案二:简化布局层级
既然外层已经用了SingleChildScrollView实现整体滚动,内部的ListView都设置了NeverScrollableScrollPhysics,可以把内层的ListView替换成Column,直接遍历_sets生成ListTile,这样布局层级更简单,也能避免嵌套ListView的高度计算问题:
// 替换内层的ListView.builder为Column Column( children: _exercises[_index].sets.asMap().entries.map((entry) { int _index2 = entry.key; var set = entry.value; return ListTile( leading: Text("Sæt " + (_index2 + 1).toString()), trailing: Text(set.reps.toString() + " reps"), tileColor: Colors.grey, onTap: () { _repsPopUp(_index, _index2); }, title: Text(_exercises[_index].name), onLongPress: () { setState(() { _exercises[_index].sets.removeAt(_index2); if (_exercises[_index].sets.isEmpty) { _exercises.removeAt(_index); } }); }, ); }).toList(), )
内容的提问来源于stack exchange,提问作者Mathias Frihauge
相关产品推荐
相关产品推荐

