简介
SliverGrid 是 CustomScrollView 中用于显示网格布局的组件。它可以创建固定大小或者可变大小的网格项,常用于展示图片、商品等网格布局。
基本用法
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, // 横轴三个子widget
mainAxisSpacing: 10.0, // 主轴方向的间距
crossAxisSpacing: 10.0, // 横轴方向子widget之间的间距
childAspectRatio: 1.0, // 子widget宽高比例
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
color: Colors.primaries[index % Colors.primaries.length],
child: Center(
child: Text('$index'),
),
);
},
childCount: 20,
),
)
网格代理类型
SliverGridDelegateWithFixedCrossAxisCount
固定列数的网格布局。
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 1.0,
)
SliverGridDelegateWithMaxCrossAxisExtent
固定最大宽度的网格布局。
SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 1.0,
)
常用属性
crossAxisCount
横轴的网格数量。
mainAxisSpacing
主轴方向的间距。
crossAxisSpacing
横轴方向的间距。
childAspectRatio
子项的宽高比。
使用场景
- 图片墙展示
- 商品网格展示
- 应用图标网格布局
完整示例
class SliverGridDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
title: Text('SliverGrid Demo'),
floating: true,
),
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 1.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Card(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.image,
size: 40,
color: Colors.primaries[index % Colors.primaries.length],
),
SizedBox(height: 8),
Text('Item $index'),
],
),
);
},
childCount: 30,
),
),
],
),
);
}
}
进阶用法
1. “瀑布流”做不出来?先理解 delegate 的限制
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 0.8,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
// 注意:这里手设 height 是无效的——
// SliverGrid 的每个格子尺寸由 delegate 的 childAspectRatio 统一决定,
// 子项自己写的高度会被忽略,所有格子等高。
height: (index % 2 + 1) * 100.0,
color: Colors.primaries[index % Colors.primaries.length],
child: Center(child: Text('Item $index')),
);
},
childCount: 20,
),
)
真想做高低不一的瀑布流(masonry),原生 SliverGrid 做不到,需要第三方包
flutter_staggered_grid_view的SliverMasonryGrid(GridView 篇”瀑布流布局”节有同样的说明)。
2. 响应式网格
LayoutBuilder(
builder: (context, constraints) {
return SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: constraints.maxWidth > 600 ? 4 : 2, // 根据宽度调整列数
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 1.0,
),
delegate: SliverChildBuilderDelegate(
(context, index) => Container(
color: Colors.primaries[index % Colors.primaries.length],
child: Center(child: Text('Item $index')),
),
childCount: 20,
),
);
},
)
性能优化建议
- 使用 SliverChildBuilderDelegate 而不是 SliverChildListDelegate
- 避免在网格项中进行复杂计算
- 合理设置网格项大小,避免过大导致性能问题
- 使用图片缓存来优化图片加载
注意事项
- 注意网格项的大小计算
- 合理设置 childAspectRatio
- 处理好网格项的状态管理
- 注意内存管理,避免创建过多网格项
实战案例:商品双列网格,GridView 和 SliverGrid 选哪个
电商 App 的商品列表经常是双列网格,GridView 和 SliverGrid 我都用过,取舍只看一句话:页面里除了网格还有没有别的东西。如果整页就是个网格,GridView 足够(它内部本来就是用 SliverGrid 实现的,文档和源码都这么写);但如果页面是”轮播横幅加分类横滑加双列商品”的多段式布局,就必须上 CustomScrollView 加 SliverGrid,让整页只有一套滚动物理,滑动才跟手。网格代理的取舍也有讲究:SliverGridDelegateWithFixedCrossAxisCount 写死列数,手机竖屏双列最常用;WithMaxCrossAxisExtent 按最大宽度自动算列数,平板和横屏适配更省心,我一般用后者兜底。delegate 则一律用 SliverChildBuilderDelegate 按需构建,商品数据来自接口,SliverChildListDelegate 的全量构建扛不住。
参考:Flutter 官方文档(api.flutter.dev)SliverGrid、GridView 类。
总结
SliverGrid 是一个强大的网格布局组件,通过合理配置可以实现各种网格效果。在使用时需要注意性能优化和布局计算。
