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

为何SliverGrid滚动动画表现不如shrinkWrap模式的GridView?

Flutter SliverGrid滚动掉帧反而不如嵌套GridView流畅的原因解析

问题场景

开发电商首页时,尝试两种方式实现畅销商品网格展示,出现了反直觉的性能表现:

  • 直接用CustomScrollView搭配SliverGrid:初始页面构建性能更优,但滚动过程中掉帧明显,动画卡顿
  • 用SliverToBoxAdapter包裹GridView(设置shrinkWrap: true、physics: NeverScrollableScrollPhysics()):初始构建开销稍大,但滚动动画更流畅

附核心代码实现:

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        const SliverAppBar(
          flexibleSpace: TopSection(),
          expandedHeight: 300,
          automaticallyImplyLeading: false,
          collapsedHeight: 70,
        ),

        // 嵌套的GridView方案
        SliverToBoxAdapter(
          child: GridView.count(
            padding: EdgeInsets.zero,
            shrinkWrap: true,
            physics: const NeverScrollableScrollPhysics(),
            crossAxisCount: 2,
            crossAxisSpacing: GSizes.gridViewSpacing,
            mainAxisSpacing: GSizes.gridViewSpacing,
            childAspectRatio: 0.55,
            children: [for (var i = 0; i < 50; i++) const ProductVerticalTile()],
          ),
        ),

        SliverToBoxAdapter(child: SizedBox(height: 50,),),

        // SliverGrid方案
        SliverGrid.count(                                    
          crossAxisCount: 2,
          childAspectRatio: 0.55,
          children: [for (var i = 0; i < 50; i++) const ProductVerticalTile()],
        )
      ],
    );
  }
}

性能对比图

GridView滚动性能:
GridView滚动性能

SliverGrid滚动性能:
SliverGrid滚动性能

核心原因分析

  1. 按需构建 vs 一次性构建的开销差异
    SliverGrid是按需渲染的,只有当子组件进入可视区域时才会创建/复用。如果ProductVerticalTile包含复杂布局、图片加载或状态逻辑,滚动过程中频繁的组件创建/重建会占用帧处理时间,导致掉帧。而shrinkWrap: true的GridView会一次性构建所有50个组件,初始构建开销大,但滚动时仅需处理位置偏移,无需动态创建组件,因此动画更流畅。

  2. 滚动协调的额外成本
    作为CustomScrollView的直接子组件,SliverGrid需要和其他Sliver(如SliverAppBar)进行滚动联动,处理偏移计算、AppBar展开/折叠状态同步等逻辑,这部分协调工作在滚动时会增加额外的性能开销。而嵌套的GridView完全禁用了自身滚动,所有滚动逻辑由外层CustomScrollView统一处理,避免了跨组件的滚动协调成本。

  3. 组件复用机制的效率问题
    如果ProductVerticalTile未正确使用const修饰或未设置唯一Key,SliverGrid滚动时可能无法有效复用现有组件,而是频繁销毁重建。而一次性构建的GridView所有组件已加载完成,滚动时仅做位置移动,无重建开销。

优化建议

  • 优化子组件实现:确保ProductVerticalTile尽可能用const修饰,或使用AutomaticKeepAliveClientMixin保持组件状态,减少滚动时的重建次数。
  • 改用SliverGrid.builder:替换SliverGrid.count为SliverGrid.builder,通过itemBuilder按需构建,并为每个item设置唯一Key,提升组件复用效率。
  • 测试大数据量场景:当商品数量超过100个时,一次性构建的GridView会导致初始卡顿加剧,此时SliverGrid的按需构建优势会更明显,可根据实际业务数据量选择方案。

内容的提问来源于stack exchange,提问作者Ahmed Gamil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 02:27:47