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

93 lines
3.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 【Demo】GridView 网格布局(三种构造)
> 源文件:`lib/pages/demo/grid_demo.dart` | 分类:基础布局
> 一句话:九宫格/相册/功能宫格都靠它,三种构造方式一次看懂。
---
## 一、这个 Demo 解决什么问题
"功能宫格(4×2 图标)"、"相册缩略图(3 列)"、"课程卡片墙"这类**多列等宽网格**布局。
GridView 就是 Flutter 的网格容器,支持**懒加载**,大量数据不卡。
---
## 二、怎么运行 / 演示内容
```dart
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. 核心参数
```dart
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](sliver_demo.md))。
---
## 四、关键代码剖析
```dart
// 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](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](list_demo.md) 的列表刷新)。
---
## 六、扩展思考
- **`SliverGridDelegateWithMaxCrossAxisExtent`**:同 extent 效果的另一种 delegate 写法;
- 相册九宫格真实案例见 [note_picker_demo.md](note_picker_demo.md):
GridView + "加号格" + 右上角删除角标(Stack 组合),多一格用 `itemCount: _images.length + 1`;
- 性能提示:builder 系列(builder/extent.builder)是懒加载,`count` 不是 —— 大列表务必 builder。