Flutter 滚动体系完全指南|SingleChildScrollView / ListView / CustomScrollView / Sliver 全套详解


在 Flutter 开发中,滚动组件是页面搭建的核心基石。几乎所有 App 都离不开列表、滚动页面、复杂视差折叠、吸顶布局。
很多开发者只会简单使用ListView,但不知道:
-
什么时候用 SingleChildScrollView
-
ListView 四种构造的性能差异
-
为什么 Column 嵌套 ListView 会报错
-
复杂折叠、吸顶、混合布局必须用 CustomScrollView + Sliver
一、Flutter 滚动体系整体架构
Flutter 滚动组件分为三大层级:
1. 基础滚动
SingleChildScrollView:一次性渲染全部子组件,适合少量静态页面
2. 常规列表滚动
ListView / GridView:自带懒加载,适合单一列表、网格业务
3. 高级复杂滚动(Sliver 体系)
CustomScrollView + Sliver 系列:支持折叠头部、吸顶、混合布局、视差效果,适合首页、详情页、复杂页面
二、SingleChildScrollView 基础滚动
核心特点
-
只能包含一个子组件(通常嵌套 Column)
-
无懒加载机制,一次性渲染所有 Widget
-
适合:表单页、个人中心、静态长页面
-
禁止:大数据列表、长列表
基础示例
SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
children: [
Text("内容1"),
Text("内容2"),
// 大量静态组件
],
),
)
常见问题
-
内部嵌套超大数量组件会卡顿、内存溢出
-
不支持 item 回收,性能不如 ListView
三、ListView 深度详解
ListView 是 Flutter 标准线性滚动列表,自带懒加载、组件回收,是长列表首选。
3.1 ListView 四种构造方式
1)ListView() 默认构造
一次性渲染所有 children,无懒加载,仅适合少量数据。
ListView(
children: [
ListTile(title: Text("条目1")),
ListTile(title: Text("条目2")),
],
)
2)ListView.builder
按需构建可视区域 Item,滑出屏幕立即销毁,带有懒加载,大数据首选。
ListView.builder(
itemCount: 1000,
itemBuilder: (context, index) {
return ListTile(title: Text("数据 $index"));
},
)
3)ListView.separated 带分割线懒加载
在 builder 基础上支持自定义分割线,项目最常用。
ListView.separated(
itemCount: 20,
itemBuilder: (ctx, idx) => ListTile(title: Text("数据 $idx")),
separatorBuilder: (ctx, idx) => Divider(height: 1),
)
4)ListView.custom 自定义
基于SliverChildDelegate,可自定义缓存、回收策略,底层所有 ListView 都基于它封装。
3.2 ListView 核心属性详解
scrollDirection 滚动方向
-
Axis.vertical:默认垂直
-
Axis.horizontal:水平列表
shrinkWrap
-
false(默认):占满父容器,拥有完整懒加载
-
true:自适应内容高度,失去懒加载能力
场景:ListView 嵌套 ListView 必须开启,但大数据慎用。
itemExtent 固定条目尺寸
提前指定 item 高度/宽度,Flutter 无需实时计算尺寸,大幅提升长列表性能。
physics 滚动物理效果
-
BouncingScrollPhysics:iOS 回弹
-
ClampingScrollPhysics:Android 边界停止
-
NeverScrollableScrollPhysics:禁止滚动
-
AlwaysScrollableScrollPhysics:内容不足也可拉动
3.3 ScrollController 滚动监听与控制
用于监听滚动偏移、代码滚动、触底加载、回到顶部。
核心能力
-
offset:当前滚动距离
-
maxScrollExtent:最大滚动区域
-
animateTo:平滑滚动
-
jumpTo:无动画跳转
完整示例
class ListDemo extends StatefulWidget {
State<ListDemo> createState() => _ListDemoState();
}
class _ListDemoState extends State<ListDemo> {
late ScrollController _controller;
void initState() {
super.initState();
_controller = ScrollController();
_controller.addListener(() {
// 触底判断
if (_controller.offset >= _controller.position.maxScrollExtent – 20) {
print("触发上拉加载");
}
});
}
//销毁防泄漏
void dispose() {
_controller.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(
onPressed: () {
_controller.animateTo(0, duration: Duration(milliseconds: 200), curve: Curves.ease);
},
child: Text("回到顶部"),
),
Expanded(
child: ListView.builder(
controller: _controller,
itemCount: 50,
itemBuilder: (_, idx) => ListTile(title: Text("item $idx")),
),
)
],
);
}
}
3.4 ListView 常见报错与解决方案
Q1:Vertical viewport was given unbounded height
原因:Column / Row 嵌套 ListView,滚动组件无边界约束
解决:ListView 外层包裹 Expanded
Q2:列表溢出、卡顿
解决:禁用 shrinkWrap、使用 builder、设置 itemExtent
四、Flutter 高级滚动:CustomScrollView + Sliver
4.1 为什么需要 Sliver?
普通 ListView / GridView 只能单一滚动布局。
业务中常见的:折叠头部 + 吸顶导航 + 轮播 + 列表 + 网格混合页面,普通组件完全无法实现。
于是 Flutter 提供 Sliver 碎片滚动体系:
-
所有组件共享同一个滚动视口
-
支持折叠、拉伸、粘性吸顶
-
支持混合多种布局联动滚动
4.2 Box 组件 vs Sliver 组件
| Box 常规组件 | ListView、Column、Container | 简单单一布局 |
| Sliver 滚动碎片 | SliverList、SliverAppBar、SliverPersistentHeader | 复杂滚动、折叠、吸顶、混合布局 |
4.3 常用 Sliver 组件对照表
| SliverAppBar | 折叠、拉伸、悬浮导航栏 | AppBar |
| SliverList | 懒加载列表 | ListView.builder |
| SliverGrid | 网格布局 | GridView.builder |
| SliverToBoxAdapter | 适配普通 Widget | 占位容器 |
| SliverPersistentHeader | 粘性吸顶头部 | 无 |
| SliverPadding | Sliver 内边距 | Padding |
核心禁忌:CustomScrollView 中不能直接放 Container/Text,普通组件必须包裹 SliverToBoxAdapter
4.4 SliverAppBar 折叠导航核心参数
SliverAppBar(
expandedHeight: 200, // 展开最大高度
pinned: true, // 收缩后固定在顶部(最常用)
floating: false,
stretch: true, // 下拉拉伸效果
flexibleSpace: FlexibleSpaceBar(
title: Text("折叠标题"),
background: Container(color: Colors.blue),
),
)
4.5 SliverPersistentHeader 粘性吸顶
实现滚动标题常驻顶部效果,必须自定义 Delegate
4.6 完整高级混合滚动 Demo
功能:折叠头部 + 吸顶标题 + 普通区域 + 网格 + 列表
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(home: SliverPage(), debugShowCheckedModeBanner: false);
}
}
class SliverPage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
// 1. 折叠头部
SliverAppBar(
expandedHeight: 200,
pinned: true,
stretch: true,
flexibleSpace: FlexibleSpaceBar(
title: Text("Sliver 高级滚动页面"),
background: Container(color: Colors.teal),
),
),
// 2. 吸顶标题
SliverPersistentHeader(
pinned: true,
delegate: MyHeaderDelegate(
height: 48,
child: Container(
color: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 16),
alignment: Alignment.centerLeft,
child: Text("🔥 网格专区", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
),
),
),
// 3. 普通组件区域
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.all(16),
child: Text("下面是网格布局演示"),
),
),
// 4. 网格布局
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
delegate: SliverChildBuilderDelegate(
(_, idx) => Container(
color: Colors.primaries[idx % Colors.primaries.length],
child: Center(child: Text("网格 $idx")),
),
childCount: 6,
),
),
// 第二个吸顶标题
SliverPersistentHeader(
pinned: true,
delegate: MyHeaderDelegate(
height: 48,
child: Container(
color: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 16),
alignment: Alignment.centerLeft,
child: Text("📃 列表数据", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
),
),
),
// 5. 列表布局
SliverList(
delegate: SliverChildBuilderDelegate(
(_, idx) => ListTile(title: Text("列表条目 $idx")),
childCount: 30,
),
)
],
),
);
}
}
// 吸顶 Header 委托
class MyHeaderDelegate extends SliverPersistentHeaderDelegate {
final Widget child;
final double height;
MyHeaderDelegate({required this.child, required this.height});
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) => child;
double get maxExtent => height;
double get minExtent => height;
bool shouldRebuild(covariant MyHeaderDelegate oldDelegate) {
return oldDelegate.child != child || oldDelegate.height != height;
}
}
五、Flutter 滚动组件选型终极标准
1. 少量静态页面
✅ SingleChildScrollView
2. 简单列表、大数据列表、瀑布流
✅ ListView / GridView(builder 模式)
3. 需要折叠头部、吸顶、混合布局、视差效果
✅ CustomScrollView + Sliver 全套体系
六、滚动组件性能优化总结
长列表必须使用 builder 懒加载
固定 item 高度优先设置 itemExtent
尽量避免shrinkWrap: true
ScrollController 页面销毁必须 dispose
复杂页面优先 Sliver 体系,减少多层嵌套滚动
itemBuilder 内不创建新对象、不做耗时操作
七、总结
Flutter 滚动三件套:
-
基础滚动:SingleChildScrollView
-
常规列表滚动:ListView 四种构造、滚动监听、性能优化
-
高级复杂滚动:CustomScrollView + 全套 Sliver 组件、折叠、吸顶、混合布局
网硕互联帮助中心


![打卡信奥刷题(3488)用C++实现信奥题 P10725 [GESP202406 八级] 最远点对-网硕互联帮助中心](https://www.wsisp.com/helps/wp-content/uploads/2026/08/20260804010041-6a7139b908d5e-220x150.png)


评论前必须登录!
注册