Files
App.K12.Student.Miniapp_Flu…/docs/demos/sliver_demo.md
T
2026-09-04 15:22:20 +08:00

115 lines
4.1 KiB
Markdown
Raw 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】CustomScrollView + Sliver 混排布局
> 源文件:`lib/pages/demo/sliver_demo.dart` | 分类:基础布局
> 一句话:折叠 AppBar + 网格 + 长列表"整页只滚一次",靠 Sliver 碎片拼装。
---
## 一、这个 Demo 解决什么问题
页面要同时包含"可折叠的大图 AppBar + 网格区块 + 长列表区块"时:
- **ListView 不能嵌套 ListView/GridView**(同向滚动会冲突,控制权打架);
- 正解是 `CustomScrollView`:把所有区块变成 Sliver"碎片"拼在一起,**共用一个滚动控制器,整页只滚一次**。
---
## 二、怎么运行 / 演示内容
```dart
runApp(const MaterialApp(home: SliverDemoPage()));
```
页面从上到下:折叠大图 AppBar → 网格标题 → 12 格网格 → 列表标题 → 50 条列表,
下滑时 AppBar 收起固定,其余内容连续滚动。
---
## 三、核心知识点(新手向)
### 1. Sliver 是什么
Sliver = "碎片"。`CustomScrollView` 把多个 sliver 拼成一个统一滚动视图。
### 2. 常用 sliver 对照表
| Sliver | 作用 | 对应普通组件 |
|---|---|---|
| `SliverAppBar` | 可折叠/固定的 AppBar | AppBar |
| `SliverToBoxAdapter` | 把普通组件(文字/卡片)塞进滚动流 | 任意 Widget |
| `SliverGrid.builder` | 网格区块(懒加载) | GridView |
| `SliverList.builder` | 列表区块(懒加载) | ListView.builder |
| `SliverPadding` | 给某个 sliver 加内边距 | Padding |
### 3. 核心结构
```dart
CustomScrollView(
slivers: [
SliverAppBar( // ① 折叠 AppBar
expandedHeight: 180.h,
pinned: true, // 滚动时固定在顶部
flexibleSpace: FlexibleSpaceBar(
title: Text('Sliver 系列 Demo'),
background: DecoratedBox(...), // 展开时的大图
),
),
SliverToBoxAdapter( // ② 普通文字标题
child: Padding(...Text('网格区块(SliverGrid)')),
),
SliverPadding( // ③ 网格区块(带外边距)
padding: EdgeInsets.all(16.w),
sliver: SliverGrid.builder(...),
),
SliverList.builder( // ④ 列表区块
itemCount: 50,
itemBuilder: ...,
),
],
)
```
### 4. 判断口诀(什么时候用 Sliver)
- 页面是"**一个网格**"或"**一个列表**" → `GridView` / `ListView` 更简单;
- 页面是"**折叠头 + 网格 + 长列表**"混排 → `CustomScrollView + slivers`。
---
## 四、关键代码剖析
### 折叠 AppBar(本页的灵魂)
```dart
SliverAppBar(
expandedHeight: 180.h, // 展开时高度(大图区域)
pinned: true, // 上滑时缩成一条标题栏并固定在顶部
backgroundColor: Color(0xFF3B82F6),
flexibleSpace: FlexibleSpaceBar(
title: Text('Sliver 系列 Demo'),
centerTitle: true,
background: DecoratedBox( // 展开时显示的大图(这里是渐变)
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFF3B82F6), Color(0xFF8E6FE8)],
),
),
),
),
)
```
---
## 五、踩坑记录
1. **slivers 里的组件必须是 Sliver 家族**,普通 Widget(如 Container)直接放会报类型错误——
要用 `SliverToBoxAdapter` 包一层;
2. **同向嵌套滚动是禁区**:CustomScrollView 里不能再放 ListView/GridView;
3. `SliverAppBar` 不设 `pinned` 时,上滑后 AppBar 会完全滚出屏幕(floating 可以浮回)——按产品需求选;
4. Sliver 的懒加载与 GridView/ListView 相同:builder 系列才懒加载。
---
## 六、扩展思考
- **Sliver 与 GridView 的本质关系**(重点记忆):
`GridView = CustomScrollView + 1 个 SliverGrid`,两者都是"单个滚动 + 懒加载",区别只在混排能力;
- 进阶 Sliver:`SliverPersistentHeader`(吸顶 Tab)、`SliverAnimatedList`(增删动画列表)、`SliverAppBar` 的 `snap` 模式;
- 电商首页 = Sliver 混排的教科书场景:搜索栏吸顶 + 轮播 + 宫格 + 瀑布流商品;
- 对照 [responsive_demo.md](responsive_demo.md):Sliver 解决"滚动结构",响应式解决"不同宽度下的结构",两者可叠加。