Flutter中如何在ExpansionPanelList内嵌套ListView.builder及Tab组件解决渲染报错
问题原因
这个hasSize报错核心是多层滚动嵌套时的高度约束丢失:
- ExpansionPanel的body本身没有固定高度,会根据子控件的高度自适应
- TabBarView默认会尽可能占满父控件提供的所有可用高度,但父级Column在无高度约束的环境下,Flexible无法正常分配高度,导致TabBarView拿到的高度是无限大,无法完成布局
- 如果你内部的
listItems()返回的是ListView,默认也会尝试占满父高度,双重无界约束就触发了布局报错
修复方案
第一步:给TabBarView添加明确高度约束
把ExpansionPanel的body部分代码修改,用SizedBox给TabBarView指定固定高度,替换原来的Flexible包裹:
body: Column( mainAxisSize: MainAxisSize.min, // 让Column高度自适应子控件 children: [ tabView(), SizedBox( // 高度根据业务需求调整,比如单页列表要展示5个项就设为 单条目高度*5 height: 400, child: tabBarView(), ), ], ),
第二步:给TabBarView内部的ListView加滚动约束
修改listItems()方法,给内部的ListView添加两个属性:
Widget listItems() { return ListView.builder( shrinkWrap: true, // 让ListView高度自适应子项总高度,不会强制占满父高度 // 如果你需要TabBarView内部的列表独立滚动就删除下面这行,如果要整个ExpansionPanel一起滚动就保留 physics: NeverScrollableScrollPhysics(), // 以下保留你原有业务代码 itemCount: 10, itemBuilder: (context, index) => ListTile(title: Text("条目$index")), ); }
可选优化:动态适配高度
如果不想写死高度,可以用IntrinsicHeight包裹整个body的Column,注意这个控件有一定布局性能损耗,适合子项数量不多的场景:
body: IntrinsicHeight( child: Column( mainAxisSize: MainAxisSize.min, children: [ tabView(), Expanded(child: tabBarView()), ], ), )
额外注意点
- TabController需要和当前页面的TickerProvider绑定,不要遗漏State类的
with SingleTickerProviderStateMixin声明 - 如果ExpansionPanelList本身是放在另一个滚动容器(比如ListView、CustomScrollView)中,需要给ExpansionPanelList添加
shrinkWrap: true和physics: NeverScrollableScrollPhysics()属性 - 你现有
tabView方法里的PreferredSize组件在Column子节点中不会生效,只有作为Scaffold.appBar的bottom参数时才会生效,可以直接去掉PreferredSize外层,保留内部的Container即可
内容的提问来源于stack exchange,提问作者Vinay Bakle
相关产品推荐
相关产品推荐

