You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 04:50:24