Flutter长列表滚动时ExpansionTile自动收起问题如何解决?
问题原因
- ExpansionTile默认内部自行维护展开状态,当ListView滚动时,超出视口范围的组件会被Flutter系统回收重建,重建后的ExpansionTile会恢复到默认的收起状态,导致之前的展开状态丢失。
- 你添加的
AutomaticKeepAliveClientMixin是用于PageView/TabBarView的子页面整体保活,无法作用于ListView内部的单个子组件,所以无法解决该问题。
修复步骤
- 首先在
MyAppState中新增状态列表,存储每一天对应ExpansionTile的展开状态:
// 下标0对应周一,1对应周二,以此类推到5对应周六 List<bool> _expansionStatus = List.filled(6, false);
- 给每一个ExpansionTile添加
initiallyExpanded和onExpansionChanged参数,绑定外部维护的状态:
以周一的ExpansionTile为例,修改后代码如下:
Theme( data: Theme.of(context).copyWith(dividerColor: Colors.transparent), child: ExpansionTile( initiallyExpanded: _expansionStatus[0], // 绑定对应下标的展开状态 onExpansionChanged: (value) { setState(() { _expansionStatus[0] = value; }); }, title: const Text( 'Monday', style: TextStyle(fontWeight: FontWeight.bold), ), children: _getChildren(4, arrMondayOutlet), ), ),
剩余周二到周六的ExpansionTile依次把下标改为1~5即可。
3. 冗余代码清理:你在main函数里已经套了一层MaterialApp,build方法里又返回了一次MaterialApp,属于重复嵌套,直接把build里的外层MaterialApp去掉,直接返回Scaffold即可,避免出现主题、路由配置冲突的问题。
可选优化建议
Days类的属性建议明确指定类型,不要用var声明,可以避免后续开发中的类型安全问题。- 可以把周一到周六的数据源、标题封装成一个统一的列表,用循环生成ExpansionTile,减少重复代码量。
内容的提问来源于stack exchange,提问作者Kuldeep
相关产品推荐
相关产品推荐

