https://api.flutter.dev/flutter/widgets/GridView-class.html
当数据量很大的时候用矩阵方式排列比较清晰。此时我们可以用网格列表组件GridView 实现布局。
GridView可以构建一个二维网格列表,其默认构造函数定义如下:
GridView({Axis scrollDirection = Axis.vertical, //滚动方向bool reverse = false,ScrollController controller,bool primary,ScrollPhysics physics,bool shrinkWrap = false,EdgeInsetsGeometry padding,@required SliverGridDelegate gridDelegate, //控制子widget layout的委托bool addAutomaticKeepAlives = true,bool addRepaintBoundaries = true,double cacheExtent,List<Widget> children = const <Widget>[],})
gridDelegate 类型是 SliverGridDelegate ,作用是控制子控件的排列。
SliverGridDelegate是一个抽象类,定义了GridView Layout相关接口,子类需要通过实现它们来实现具体的布局算法。有2个选择:
SliverGridDelegateWithFixedCrossAxisCount:交叉轴方向上固定数量,对于垂直方向的GridView来说交叉轴方向指的是水平方向。SliverGridDelegateWithMaxCrossAxisExtent:交叉轴方向上尽量大,比如水平方上有500空间,指定此值为150,那么可以放3个,剩余一些空间,此时GridView将会缩小每一个Item,放置4个。
SliverGridDelegateWithFixedCrossAxisCount
该子类实现了一个横轴为固定数量子元素的layout算法,其构造函数为:
SliverGridDelegateWithFixedCrossAxisCount({@required double crossAxisCount,double mainAxisSpacing = 0.0,double crossAxisSpacing = 0.0,double childAspectRatio = 1.0,})
mainAxisSpacing主轴方向的间距。crossAxisSpacing交叉轴方向上之间的间隔。crossAxisCount交叉轴方向上子元素的数量。childAspectRatio子控件宽高比。
示例

GridView(gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3,crossAxisSpacing: 5.0,mainAxisSpacing: 10.0,childAspectRatio: 16 / 5,),children: List.generate(10,(index) => Container(color: Colors.primaries[index % Colors.primaries.length],child: Text('数据 $index'),),),),
GridView.count
GridView.count构造函数内部使用了SliverGridDelegateWithFixedCrossAxisCount,我们通过它可以快速的创建横轴固定数量子元素的GridView,上面的示例等同于:
GridView.count(crossAxisCount: 3,crossAxisSpacing: 5.0,mainAxisSpacing: 10.0,childAspectRatio: 16 / 5,// children: ...,),
SliverGridDelegateWithMaxCrossAxisExtent
该子类实现了一个横轴子元素为固定最大长度的layout算法,其构造函数为:
SliverGridDelegateWithMaxCrossAxisExtent({double maxCrossAxisExtent,double mainAxisSpacing = 0.0,double crossAxisSpacing = 0.0,double childAspectRatio = 1.0,})
maxCrossAxisExtent为子元素在横轴上的最大长度,之所以是“最大”长度,是因为主轴方向每个子元素的长度仍然是等分的。
示例
如果ViewPort的横轴长度是480,那么当maxCrossAxisExtent的值在区间[480/4,480/3)内的话,子元素最终实际长度都为 480 / 4。
GridView(gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(maxCrossAxisExtent: 150,crossAxisSpacing: 5.0,mainAxisSpacing: 10.0,childAspectRatio: 16 / 5,),children: List.generate(10,(index) => Container(color: Colors.primaries[index % Colors.primaries.length],child: Text('数据 $index'),),),),
GridView.extent
GridView.extent构造函数内部使用了SliverGridDelegateWithMaxCrossAxisExtent,我们通过它可以快速的创建纵轴子元素为固定最大长度的的GridView,上面的示例代码等价于:
GridView.extent(maxCrossAxisExtent: 150,crossAxisSpacing: 5.0,mainAxisSpacing: 10.0,childAspectRatio: 16 / 5,// children: ...,);
GridView.builder
上面我们介绍的GridView都需要一个widget数组作为其子元素,这些方式都会提前将所有子widget都构建好,所以只适用于子widget数量比较少时,当子widget比较多时,我们可以通过GridView.builder来动态创建子widget。GridView.builder 必须指定的参数有两个:
GridView.builder(...@required SliverGridDelegate gridDelegate,@required IndexedWidgetBuilder itemBuilder,itemCount,)
其中itemBuilder为子widget构建器。
示例:
假设我们需要从一个异步数据源(如网络)分批获取一些数据,然后用GridView来展示:
import "package:flutter/material.dart";import "package:english_words/english_words.dart";class TestPage extends StatefulWidget {@override_TestPageState createState() => _TestPageState();}class _TestPageState extends State<TestPage> {var _myData = [];@overridevoid initState() {super.initState();_getData();}//模拟异步获取数据_getData() {Future.delayed(Duration(seconds: 2)).then((val) {setState(() {var generateWords = generateWordPairs().take(10);var words = generateWords.map((v) => v.asPascalCase).toList();_myData.addAll(words);});});}@overrideWidget build(BuildContext context) {return GridView.builder(gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3,childAspectRatio: 4,),itemCount: _myData.length,itemBuilder: (context, index) {return Container(color: Colors.primaries[index % Colors.primaries.length],child: Text('单词 ${_myData[index]}'),);},);}}
更多
Flutter的GridView默认子元素显示空间是相等的,但在实际开发中,你可能会遇到子元素大小不等的情况,如下面这样的布局:
Pub上有一个包“flutter_staggered_grid_view” ,它实现了一个交错GridView的布局模型,可以很轻松的实现这种布局。
