带组头的列表¶
以下所有实例都是在CustomScrollView
组件的slivers
属性中实现的。
SliverPersistentHeader+SliverList¶
实现类似于 iOS 中带有组头的列表,可以使用 ListView
或 CustomScrollView
结合 SliverList
和 SliverPersistentHeader
。
import 'package:flutter/material.dart';
class GroupedListView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: <Widget>[
SliverPersistentHeader(
pinned: true,
delegate: _SliverAppBarDelegate(
minHeight: 60.0,
maxHeight: 60.0,
child: Container(
color: Colors.lightBlue,
child: Center(child: Text('Group 1 Header')),
),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return ListTile(
title: Text('Item #$index in Group 1'),
);
},
childCount: 5,
),
),
SliverPersistentHeader(
pinned: true,
delegate: _SliverAppBarDelegate(
minHeight: 60.0,
maxHeight: 60.0,
child: Container(
color: Colors.lightGreen,
child: Center(child: Text('Group 2 Header')),
),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return ListTile(
title: Text('Item #$index in Group 2'),
);
},
childCount: 5,
),
),
],
);
}
}
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate({
required this.minHeight,
required this.maxHeight,
required this.child,
});
final double minHeight;
final double maxHeight;
final Widget child;
@override
double get minExtent => minHeight;
@override
double get maxExtent => maxHeight;
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return SizedBox.expand(child: child);
}
@override
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
return maxHeight != oldDelegate.maxHeight ||
minHeight != oldDelegate.minHeight ||
child != oldDelegate.child;
}
}
在这个示例中:
- CustomScrollView
用于创建一个可滚动的视图。
- SliverPersistentHeader
用于创建固定的组头。
- SliverList
用于创建每个组中的列表项。
SliverPersistentHeader+SliverGrid¶
要实现一个带有组头和分组数据的页面,并且每行最多显示四个项目。
-
使用
CustomScrollView
作为主容器。 -
使用
SliverPersistentHeader
来显示组头。 - 使用
SliverGrid
来显示每个组中的项目。
如果需要调整布局和样式,可以修改相应的参数和样式属性。
import 'package:flutter/material.dart';
class GroupedGridView extends StatelessWidget {
// 数据源
final List<Map<String, List<String>>> data = [
{
'食品酒水': ['早午晚餐', '烟酒茶', '水果零食'],
},
{
'行车交通': ['公共交通', '打车租车', '私家车费用'],
},
{
'居家物业': ['日常用品', '水电煤气', '房租', '物业管理', '维修保养'],
},
];
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: <Widget>[
// 遍历数据源,生成组头和对应的网格
for (var section in data)
...section.entries.map((entry) {
return [
SliverPersistentHeader(
pinned: true,
delegate: _SliverAppBarDelegate(
minHeight: 50.0,
maxHeight: 50.0,
child: Container(
color: Colors.lightBlue,
child: Center(
child: Text(
entry.key,
style: TextStyle(color: Colors.white, fontSize: 18),
),
),
),
),
),
SliverPadding(
padding: EdgeInsets.all(8.0),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4, // 每行显示四个项目
mainAxisSpacing: 8.0,
crossAxisSpacing: 8.0,
childAspectRatio: 3, // 宽高比,调整项目高度
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text(entry.value[index]),
);
},
childCount: entry.value.length,
),
),
),
];
}).expand((element) => element).toList(),
],
);
}
}
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate({
required this.minHeight,
required this.maxHeight,
required this.child,
});
final double minHeight;
final double maxHeight;
final Widget child;
@override
double get minExtent => minHeight;
@override
double get maxExtent => maxHeight;
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return SizedBox.expand(child: child);
}
@override
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
return maxHeight != oldDelegate.maxHeight ||
minHeight != oldDelegate.minHeight ||
child != oldDelegate.child;
}
}
SliverToBoxAdapter+SliverGrid¶
组头和网格项都会随着页面一起滚动,而不是固定在顶部,可以使用 SliverToBoxAdapter
来替代 SliverPersistentHeader
。这样组头将成为普通的列表项,随页面一起滚动。
import 'package:flutter/material.dart';
class GroupedGridView extends StatelessWidget {
// 数据源
final List<Map<String, List<String>>> data = [
{
'食品酒水': ['早午晚餐', '烟酒茶', '水果零食'],
},
{
'行车交通': ['公共交通', '打车租车', '私家车费用'],
},
{
'居家物业': ['日常用品', '水电煤气', '房租', '物业管理', '维修保养'],
},
];
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: <Widget>[
// 遍历数据源,生成组头和对应的网格
for (var section in data)
...section.entries.map((entry) {
return [
SliverToBoxAdapter(
child: Container(
height: 50.0,
color: Colors.lightBlue,
child: Center(
child: Text(
entry.key,
style: TextStyle(color: Colors.white, fontSize: 18),
),
),
),
),
SliverPadding(
padding: EdgeInsets.all(8.0),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4, // 每行显示四个项目
mainAxisSpacing: 8.0,
crossAxisSpacing: 8.0,
childAspectRatio: 3, // 宽高比,调整项目高度
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text(entry.value[index]),
);
},
childCount: entry.value.length,
),
),
),
];
}).expand((element) => element).toList(),
],
);
}
}