Flutter大量数据场景下ExpansionPanelList性能优化问询
解决Flutter中ExpansionPanelList处理大量数据的性能问题
ExpansionPanelList本身不支持按需构建,必须一次性传入所有子组件列表。当数据量达到10000条时,会一次性创建所有ExpansionPanel实例,直接导致性能暴跌。
解决方案:用ListView.builder + ExpansionTile实现懒加载
ListView.builder只会构建当前视口内及附近的列表项,配合ExpansionTile的展开/收起特性,可以完美替代ExpansionPanelList的功能,同时解决性能问题。
修改后的实现代码:
return Form( key: _formKey, child: ListView.builder( itemCount: state.games.length, itemBuilder: (context, index) { final game = state.games[index]; final gameAddedStatus = VMGameTools.getGameStatus(game); return ExpansionTile( // 控制展开/收起状态 onExpansionChanged: (isExpanded) { _nsgpBloc.swapExpansionStateForItem(index); }, // 初始展开状态与原逻辑保持一致 initiallyExpanded: game.foldingState, canTapOnHeader: true, // 原头部布局完全复用 title: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded(child: Text(game.userGame.name, style: Theme.of(context).textTheme.headline5, textAlign: TextAlign.left)), Padding( padding: const EdgeInsets.fromLTRB(0, 0, 24, 0), child: game.userGame.isExternal ? null : Text(StringTools.bytesToStorageUnity(game.userGame.gameSize)), ), Padding( padding: const EdgeInsets.fromLTRB(0, 0, 24, 0), child: _getExeCurrentStateIcon(gameAddedStatus), ), IconButton( onPressed: () { _nsgpBloc.renameGame(context, game); }, icon: const Icon(Icons.edit), tooltip: tr("rename_game"), ), IconButton( onPressed: () { _nsgpBloc.deleteGame(context, game); }, icon: const Icon(Icons.delete), tooltip: tr("delete"), ), ], ), if(game.foldingState) Text("${game.userGame.path}", textAlign: TextAlign.left, style: TextStyle(color: themeExtension.gameCardHeaderPath, fontSize: 13),) ], ), // 原body内容放入ExpansionTile的children中 children: [ _buildGameTile(context, themeExtension, game.userGame, state.availableProntonNames), ], ); }, ), );
关键优化点说明
- 按需构建:ListView.builder仅创建可见区域内的ExpansionTile,不会一次性生成10000个组件
- 功能对齐:ExpansionTile自带展开/收起逻辑,完全覆盖原ExpansionPanel的
canTapOnHeader、isExpanded等特性 - 逻辑复用:原有的头部布局、按钮交互、body构建逻辑全部保留,无需修改核心业务代码
额外优化建议
如果_buildGameTile包含复杂组件或网络请求,可以将其封装为独立的StatefulWidget并实现AutomaticKeepAliveClientMixin,避免每次展开时重新构建内容,进一步提升流畅度。
内容的提问来源于stack exchange,提问作者Notbad
相关产品推荐
相关产品推荐

