在项目中,有时候会有诸如“日历”展示之类的需求,此时单列表ListView控件已经无法满足我们的需要。GridView就是为了满足这样的“二维数组”排列而存在的。
1、默认构造函数
代码语言:javascript复制GridView({
//与ListView相同的参数
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap = false,
EdgeInsetsGeometry padding,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
double cacheExtent,
//GridView特有属性
@required SliverGridDelegate gridDelegate, //控制子widget layout的委托
List<Widget> children = const <Widget>[],
})
GridView的大部分参数与ListView是一样的,请参见系列文章《Flutter ListView 列表控件》。
我们需要关注的是gridDelegate参数,类型是SliverGridDelegate,它的作用是控制GridView子组件如何排列(layout)。
SliverGridDelegate是一个抽象类,定义了GridView Layout相关接口。Flutter中提供了两个子类:SliverGridDelegateWithFixedCrossAxisCount和SliverGridDelegateWithMaxCrossAxisExtent,我们可以直接使用。
2、SliverGridDelegateWithFixedCrossAxisCount
属性值 | 含义 |
---|---|
crossAxisCount | 决定有网格有多少列数据 |
mainAxisSpacing | 主轴方向item之间的间隙 |
crossAxisSpacing | 非主轴方向item之间的间隙 |
childAspectRatio | 非主轴方向的item内容与主轴方向的内容宽高比默认=1.0(即1:1展示) |
@required this.crossAxisCount,
this.mainAxisSpacing = 0.0,
this.crossAxisSpacing = 0.0,
this.childAspectRatio = 1.0,
2.1、举例说明:
假设需要实现一个3列的网格(只需要固定列,行数可根据数据多少自动调节),主轴方向item间隙为20像素,非主轴方向的item间隙为10像素,非主轴方向的内容是主轴方向内容的2倍容量。我们可以这样实现:
代码语言:javascript复制 body: GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 20,
crossAxisSpacing: 10,
childAspectRatio: 2,
),
children: <Widget>[
Container(
color: Colors.green,
child: Icon(Icons.ac_unit),
),
//……此处省略7个Icon代码
Container(
color: Colors.green,
child: Icon(Icons.accessible_forward),
),
],
),
Icon外面包裹Container控件是为了设置背景颜色,让效果更直观。
效果如下:
3、SliverGridDelegateWithMaxCrossAxisExtent
属性值 | 含义 |
---|---|
maxCrossAxisExtent | 决定每一列的item占用多少像素 |
mainAxisSpacing | 主轴方向item之间的间隙 |
crossAxisSpacing | 非主轴方向item之间的间隙 |
childAspectRatio | 非主轴方向的item内容与主轴方向的内容宽高比默认=1.0(即1:1展示) |
@required this.maxCrossAxisExtent,
this.mainAxisSpacing = 0.0,
this.crossAxisSpacing = 0.0,
this.childAspectRatio = 1.0,
mainAxisSpacing、crossAxisSpacing、childAspectRatio三个参数与SliverGridDelegateWithFixedCrossAxisCount相同,这里我们主要理解maxCrossAxisExtent
的用法。
- maxCrossAxisExtent
此参数表示每一列的item占用多少像素的宽度。假设非主轴(横轴)的总像素是500,那么mainAxisSpacing = 100
表示每行可展示5列(前提是设置item间隙)。因此,可以通过控制mainAxisSpacing
的值来动态控制网格布局的列数。
3.1、举例说明:
假设将maxCrossAxisExtent设为80,主轴方向item间隙为10像素,非主轴方向的item间隙为10像素,非主轴方向的内容是主轴方向内容的2倍容量。我们可以这样实现:
代码语言:javascript复制 body: GridView(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 80,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
childAspectRatio: 2,
),
children: <Widget>[
Container(
color: Colors.green,
child: Icon(Icons.ac_unit),
),
//……此处省略7个Icon代码
Container(
color: Colors.green,
child: Icon(Icons.accessible_forward),
),
],
),
效果如下:
可以看出网格布局变成了5列,通过计算80*5 10*4=440px
得出使用宽度为440像素,剩下60像素不足以再多出一列的宽度,所以最多只能生成5列数据。
4、GridView.extent
GridView.extent
是SliverGridDelegateWithMaxCrossAxisExtent
的另一种代码表现形式(大概是因为名字太长了),它们具有相同的功能。
用法:
代码语言:javascript复制 body: GridView.extent(
maxCrossAxisExtent: 80,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
childAspectRatio: 2,
5、GridView.builder
以上GridView都需要事先排列好所有的item布局(widget),这就相当于将数据提前写死了,不方便动态拓展,也不适合数据过多的情况。当子widget比较多时,我们可以通过GridView.builder来动态创建子widget。
代码语言:javascript复制GridView.builder(gridDelegate: null, itemBuilder: null),
gridDelegate参数在上面已经讲过了,我们主要来看看itemBuilder
如何使用。
5.1、举例说明:
设置一个网格布局,拥有50个子项目,前10个项目输出索引,拥有绿色背景,之后所有项目拥有蓝色背景。
代码语言:javascript复制 child: GridView.builder(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 100,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
childAspectRatio: 2,
),
itemCount: 50,
itemBuilder: (BuildContext context, int position) {
Widget item;
if (position < 10) {
item = FlatButton.icon(
icon: Icon(Icons.info),
label: Text("" position.toString()),
color: Colors.green,
onPressed: () {},
);
} else {
item = Container(
color: Colors.blue,
child: Icon(
Icons.airplanemode_active,
color: Colors.white,
),
);
}
return item;
}),
注意:itemCount
虽然不是必选参数,实际使用时别忘记加上,它是决定子项显示数量的关键因素。
效果如下:
6、StaggeredGridView.countBuilder 瀑布流
StaggeredGridView不是Flutter提供的GridView组件,而是专门为实现瀑布流而存在的flutter_staggered_grid_view
包提供的功能。
6.1、使用步骤:
- 导入flutter_staggered_grid_view库。
pubspec.yaml
文件中导入如下代码:
dependencies:
# 瀑布流
flutter_staggered_grid_view: ^0.2.7
- 导入包到代码文件
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
- 使用
StaggeredGridView.countBuilder(
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
crossAxisCount: 4,
itemCount: 20,
itemBuilder: (BuildContext context, int index) => new Container(
color: index.isEven ? Colors.green : Colors.yellow,
child: new Center(
child: new CircleAvatar(
backgroundColor: Colors.white,
child: new Text('$index'),
),
)),
staggeredTileBuilder: (int index) =>
new StaggeredTile.count(2, index.isEven ? 2 : 1),
)
4.效果图
分析:
最主要起到瀑布流效果的是这句代码: `staggeredTileBuilder: (int index) =>
代码语言:javascript复制 new StaggeredTile.count(2, index.isEven ? 2 : 1),`
实际运用中需要根据实际情况对瀑布流item的高度进行调整。