SliverList
一个沿主轴将多个盒子子组件按线性排列的sliver
SliverList是Flutter中用于创建可滚动子项列表的Sliver组件,专为与CustomScrollView配合使用而设计。与普通的ListView不同,SliverList能够与其他Sliver组件(如SliverAppBar、SliverGrid等)协同工作,实现复杂的自定义滚动效果。
SliverList通过delegate来懒加载其子元素,只有在子元素即将出现在视口中时才会被构建,这大大提高了长列表的性能表现。它遵循Sliver协议,能够响应父滚动容器的滚动通知。
使用场景
- 复杂滚动界面: 需要与
AppBar、Grid等其他滚动元素协同工作的列表 - 长列表性能优化: 处理大量数据时使用懒加载提高性能
- 自定义滚动效果: 实现视差滚动、折叠头部等高级UI效果
- 多类型列表布局: 与其他Sliver组件组合创建混合布局
示例
1. 基础SliverList使用
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: CustomScrollView(
slivers: <Widget>[
// 滑动时折叠的AppBar
SliverAppBar(
expandedHeight: 200.0,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: Text('SliverList 示例'),
background: Image.network(
'https://picsum.photos/800/600',
fit: BoxFit.cover,
),
),
),
// SliverList 主体部分
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
child: Text('${index + 1}'),
),
title: Text('列表项 ${index + 1}'),
subtitle: Text('这是第 ${index + 1} 个列表项的描述内容'),
trailing: Icon(Icons.arrow_forward),
onTap: () {
print('点击了第 ${index + 1} 项');
},
);
},
childCount: 50, // 列表项数量
),
),
],
),
),
);
}
}
2. 多种Sliver组件组合
import 'package:flutter/material.dart';
class CombinedSliverExample extends StatelessWidget {
Widget build(BuildContext context) {
return CustomScrollView(
slivers: <Widget>[
SliverAppBar(
title: Text('混合Sliver布局'),
floating: true,
expandedHeight: 250.0,
actions: [IconButton(icon: Icon(Icons.search), onPressed: () {})],
),
// 标题部分
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text(
'热门推荐',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
),
),
// 网格布局
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
childAspectRatio: 0.8,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return Card(
child: Column(
children: [
Expanded(
child: Image.network(
'https://picsum.photos/200/300?random=$index',
fit: BoxFit.cover,
width: double.infinity,
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Text('推荐项目 $index'),
),
],
),
);
},
childCount: 6,
),
),
// 另一个标题
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text(
'全部列表',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
),
),
// 主要的SliverList
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
margin: EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.0),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 2.0,
offset: Offset(0, 1),
),
],
),
child: ListTile(
contentPadding: EdgeInsets.all(16.0),
leading: Icon(Icons.star, color: Colors.amber),
title: Text('高级功能 ${index + 1}'),
subtitle: Text('包含更多详细信息和操作选项'),
trailing: Chip(
label: Text('NEW'),
backgroundColor: Colors.blue[50],
),
),
);
},
childCount: 20,
),
),
],
);
}
}
3. 高性能无限列表
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
class InfiniteSliverList extends StatefulWidget {
_InfiniteSliverListState createState() => _InfiniteSliverListState();
}
class _InfiniteSliverListState extends State<InfiniteSliverList> {
final List<String> _items = [];
final ScrollController _scrollController = ScrollController();
bool _isLoading = false;
int _currentPage = 0;
void initState() {
super.initState();
_loadMoreItems();
_scrollController.addListener(_scrollListener);
}
void dispose() {
_scrollController.dispose();
super.dispose();
}
void _scrollListener() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_loadMoreItems();
}
}
Future<void> _loadMoreItems() async {
if (_isLoading) return;
setState(() => _isLoading = true);
// 模拟网络请求延迟
await Future.delayed(Duration(seconds: 1));
final newItems = List.generate(20, (i) => '项目 ${_items.length + i + 1}');
setState(() {
_items.addAll(newItems);
_isLoading = false;
_currentPage++;
});
}
Widget build(BuildContext context) {
return CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverAppBar(
title: Text('无限滚动列表'),
pinned: true,
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
if (index < _items.length) {
return ListTile(
title: Text(_items[index]),
leading: CircleAvatar(
child: Text('${index + 1}'),
),
);
} else if (index == _items.length && _isLoading) {
return Center(child: CircularProgressIndicator());
} else {
return SizedBox.shrink();
}
},
childCount: _items.length + (_isLoading ? 1 : 0),
),
),
],
);
}
}
注意事项
常见问题
- 性能问题:虽然
SliverList是懒加载的,但复杂的子项构建仍会影响性能 - 内存泄漏:忘记在
StatefulWidget中释放ScrollController - 布局错误:不正确的
SliverChildBuilderDelegate配置导致列表项重复或缺失 - 滚动冲突:多个滚动控制器同时使用时可能产生冲突
优化技巧
- 使用const构造函数:尽可能为列表项使用
const构造函数 - 合理使用Key:为动态列表项提供合适的
Key以提高性能 - 避免重建:使用
AutomaticKeepAliveClientMixin保持列表项状态 - 图片优化:对网络图片使用
cached_network_image等优化库
最佳实践
- 预估高度:为
SliverChildBuilderDelegate提供estimateChildExtent以提高性能 - 分离构建逻辑:将复杂的列表项构建逻辑提取到单独的
Widget中 - 错误边界:为异步加载提供错误处理和重试机制
- 空状态处理:为空的列表提供友好的用户界面
构造函数
//默认的构造函数
SliverList.new({
Key? key,
required SliverChildDelegate delegate
})
//使用itemBuilder来构建子项
SliverList.builder({
Key? key,
required NullableIndexedWidgetBuilder itemBuilder,
ChildIndexGetter? findChildIndexCallback,
int? itemCount,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true
})
//使用固定子项的构造函数
SliverList.list({
Key? key,
required List<Widget> children,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true
})
//可以添加分割线的构造函数
SliverList.separated({
Key? key,
required NullableIndexedWidgetBuilder itemBuilder,
ChildIndexGetter? findChildIndexCallback,
required NullableIndexedWidgetBuilder separatorBuilder,
int? itemCount,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true
})
属性
| 属性名 | 类型 | 说明 |
|---|---|---|
delegate | SliverChildDelegate | 负责创建和估计子项大小的委托对象 |
key | Key? | 组件的键,用于控制组件的唯一性 |
SliverChildBuilderDelegate关键属性
| 属性名 | 类型 | 说明 |
|---|---|---|
builder | NullableIndexedWidgetBuilder | 构建子项的回调函数,接收上下文和索引 |
childCount | int? | 子项总数,null 表示无限列表 |
addAutomaticKeepAlives | bool | 自动管理子项的生命周期状态 |
addRepaintBoundaries | bool | 为每个子项添加重绘边界,提高性能 |
addSemanticIndexes | bool | 为每个子项添加语义索引,辅助功能 |
estimateChildExtent | double? | 预估子项高度,优化滚动性能 |
关键属性介绍
- delegate
- 重要性: 核心属性,决定了列表的行为和性能
- 性能影响: 使用
SliverChildBuilderDelegate可实现懒加载,大幅提升长列表性能 - 使用建议: 对于固定数量的列表,提供准确的
childCount;对于动态列表,使用适当的加载策略
- estimateChildExtent
- 重要性: 高级优化属性
- 性能影响: 提供准确的预估高度可以显著改善滚动性能,特别是对于高度可变的项目
- 使用建议: 如果所有项目高度相近,提供平均高度;如果高度差异大,考虑使用
SliverPrototypeExtentList
- addRepaintBoundaries
- 重要性: 性能优化属性
- 性能影响: 设置为
true可以避免不必要的重绘,但会增加内存使用 - 使用建议: 对于简单项目可以设置为
false,复杂项目建议保持默认的true
- addAutomaticKeepAlives
- 重要性: 状态管理属性
- 性能影响: 保持项目状态可以避免重建开销,但会增加内存占用