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

Flutter ListView.builder滚动FPS过低(Android模拟器18.7)优化咨询

优化方案:解决ListView滚动时Map转换导致的性能问题

问题根源

你的代码中,itemBuilder会在ListView滚动的每一帧被频繁调用,而每次调用都执行controller.groupedList.keys.toList()和通过key查找Map的操作——这些重复计算会带来额外的性能开销,直接拉低帧率。

具体优化方案

1. 预缓存分组键与数据列表

将Map的keys转换和数据映射操作移出itemBuilder,只执行一次(或在数据更新时同步更新):

方案一:在Widget的State中缓存

late List<dynamic> _cachedKeys;

@override
void initState() {
  super.initState();
  // 仅在初始化时计算一次keys列表
  _cachedKeys = controller.groupedList.keys.toList();
}

// 后续在itemBuilder中使用
ListView.builder(
  physics: BouncingScrollPhysics(),
  controller: scrollController,
  key: _animatedKey,
  scrollDirection: Axis.vertical,
  shrinkWrap: true,
  itemCount: controller.yearOld,
  itemBuilder: (context, index) {
    var thisYearList = controller.groupedList[_cachedKeys[index]];
    return TimelineItemWidget(
        controller: controller,
        index: index,
        thisYearList: thisYearList);
  },
);

方案二:在Controller内部维护缓存结构
如果groupedList可能动态更新,建议在Controller中缓存转换后的列表,避免重复计算:

// 在你的Controller类中添加
List<dynamic>? _cachedKeys;
List<List<Event>>? _cachedGroupedLists;

List<dynamic> get cachedKeys {
  // 仅在keys为空或数据更新时重新计算
  if (_cachedKeys == null || _cachedKeys!.length != groupedList.length) {
    _cachedKeys = groupedList.keys.toList();
  }
  return _cachedKeys!;
}

List<List<Event>> get cachedGroupedLists {
  if (_cachedGroupedLists == null || _cachedGroupedLists!.length != groupedList.length) {
    _cachedGroupedLists = groupedList.values.toList();
  }
  return _cachedGroupedLists!;
}

// 使用时直接调用缓存的列表
ListView.builder(
  // ...其他参数
  itemCount: controller.cachedGroupedLists.length,
  itemBuilder: (context, index) {
    var thisYearList = controller.cachedGroupedLists[index];
    return TimelineItemWidget(
        controller: controller,
        index: index,
        thisYearList: thisYearList);
  },
);

2. 移除不必要的shrinkWrap

shrinkWrap: true会强制ListView每次滚动时重新计算所有子项的总高度,这是性能杀手之一。如果你的布局允许,尽量移除该属性,让ListView填充父容器的可用空间。

3. 优化子Widget的重建

检查TimelineItemWidget是否可以使用const构造函数(如果传入的参数都是不可变类型),或者使用AutomaticKeepAliveClientMixin避免不可见的子项被频繁销毁重建。

内容的提问来源于stack exchange,提问作者matti peter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 18:05:34