Files
2026-09-04 15:22:20 +08:00

3.5 KiB
Raw Permalink Blame History

【Demo】GridView 网格布局(三种构造)

源文件:lib/pages/demo/grid_demo.dart | 分类:基础布局 一句话:九宫格/相册/功能宫格都靠它,三种构造方式一次看懂。


一、这个 Demo 解决什么问题

"功能宫格(4×2 图标)"、"相册缩略图(3 列)"、"课程卡片墙"这类多列等宽网格布局。 GridView 就是 Flutter 的网格容器,支持懒加载,大量数据不卡。


二、怎么运行 / 演示内容

runApp(const MaterialApp(home: GridDemoPage()));

一屏并排演示三种构造:

  1. GridView.count:固定 3 列,写死 children;
  2. GridView.builder:4 列,itemCount: 100 懒加载;
  3. GridView.extent:每项最多 80 宽,屏幕越宽列数自动变多。

三、核心知识点(新手向)

1. 三个常用构造怎么选

构造 特点 适用
GridView.count 固定列数,children 一次性全创建 少量固定网格(< 30)
GridView.builder 懒加载,itemCount + itemBuilder 大量数据首选(100+ 条)
GridView.extent 按"每项最大宽度"自适应列数 响应式场景(Pad 变列数)

2. 核心参数

GridView.builder(
  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 4,        // 列数
    mainAxisSpacing: 8.w,     // 主轴(上下行)间距
    crossAxisSpacing: 8.w,    // 交叉轴(左右列)间距
    childAspectRatio: 1,      // 每项 宽:高 比例,默认 1 = 正方形
  ),
  itemCount: 100,
  itemBuilder: (context, index) => _GridItem(index: index),
)

3. 重点记忆:GridView 的本质

GridView = CustomScrollView + 1 个 SliverGrid(框架内部自动包的简化套餐)。

  • 页面只有网格 → GridView.builder 直接用;
  • 页面要混排(折叠 AppBar + 网格 + 列表)→ 用 CustomScrollView + slivers(见 sliver_demo.md)。

四、关键代码剖析

// Demo3:extent 自适应列数
GridView.extent(
  maxCrossAxisExtent: 80.w, // 每项最多 80 宽 → 屏幕宽时自动多列
  mainAxisSpacing: 8.w,
  crossAxisSpacing: 8.w,
  childAspectRatio: 1,
  children: [for (int i = 0; i < 12; i++) _GridItem(index: i)],
)

响应式网格更精细的做法见 responsive_demo.md: 用 LayoutBuilder 拿真实宽度,(width / 280).floor().clamp(1, 4) 算列数。


五、踩坑记录

  1. GridView 放 Column 里必须 SizedBox 定高或 Expanded,否则报 Vertical viewport was given unbounded height(和 ListView 同一个坑)。
  2. childAspectRatio 太小(如 0.5)时,格子内文字会被挤压溢出 —— 调大比例或缩小字号。
  3. 本页外层 SingleChildScrollView 只是"展示台"(为了并排演示 3 种构造), 真实网格页别学这个外层 —— 网格自己就能滚。
  4. 想"网格 + 下拉刷新",用 RefreshIndicator 包 GridView(写法同 list_demo.md 的列表刷新)。

六、扩展思考

  • SliverGridDelegateWithMaxCrossAxisExtent:同 extent 效果的另一种 delegate 写法;
  • 相册九宫格真实案例见 note_picker_demo.md: GridView + "加号格" + 右上角删除角标(Stack 组合),多一格用 itemCount: _images.length + 1;
  • 性能提示:builder 系列(builder/extent.builder)是懒加载,count 不是 —— 大列表务必 builder。