GridView 虽不及 ListView 用得多,但是 ListView 如果是纵向滚动的,那么在一行上一般算作一个 Item,如果是横向滚动,那么一在一列上一般算作一个 Item,如果需要一行展示多个 Item 但是又需要纵向滚动的话,就需要 GridView 了,在一些特定的情景,如展示图片的时候效果比 ListView 更棒,所以这也是个很重要的组件。
由于 GridView 很多属性跟 ListView 差不多,所有部分属性的用法可以参考 Fluutter 基础组件之 ListView
GridView({Key key, Axis scrollDirection: Axis.vertical, bool reverse: false, ScrollController controller, bool primary, ScrollPhysics physics, bool shrinkWrap: false, EdgeInsetsGeometry padding, @required SliverGridDelegate gridDelegate, bool addAutomaticKeepAlives: true, bool addRepaintBoundaries: true, bool addSemanticIndexes: true, double cacheExtent, List
构造一个 GridView,其中必传的参数为 SliverGridDelegate,相当于一个构造 GridView 的委托者,下面会解释该参数。
GridView.builder({Key key, Axis scrollDirection: Axis.vertical, bool reverse: false, ScrollController controller, bool primary, ScrollPhysics physics, bool shrinkWrap: false, EdgeInsetsGeometry padding, @required SliverGridDelegate gridDelegate, @required IndexedWidgetBuilder itemBuilder, int itemCount, bool addAutomaticKeepAlives: true, bool addRepaintBoundaries: true, bool addSemanticIndexes: true, double cacheExtent, int semanticChildCount })
根据需要来自定义创建 ListView,该构造方法多了一个必传的 itemBuilder,同 ListView 一样,它是一个 IndexedWidgetBuilder ,它的构造方法中会返回 index,可以根据这个 index 来让 ListView 的子 Item 有不同的展示。
GridView.count({Key key, Axis scrollDirection: Axis.vertical, bool reverse: false, ScrollController controller, bool primary, ScrollPhysics physics, bool shrinkWrap: false, EdgeInsetsGeometry padding, @required int crossAxisCount, double mainAxisSpacing: 0.0, double crossAxisSpacing: 0.0, double childAspectRatio: 1.0, bool addAutomaticKeepAlives: true, bool addRepaintBoundaries: true, bool addSemanticIndexes: true, double cacheExtent, List
相当于指定第一种构造方法的 gridDelegate 为 SliverGridDelegateWithFixedCrossAxisCount。
GridView.custom({Key key, Axis scrollDirection: Axis.vertical, bool reverse: false, ScrollController controller, bool primary, ScrollPhysics physics, bool shrinkWrap: false, EdgeInsetsGeometry padding, @required SliverGridDelegate gridDelegate, @required SliverChildDelegate childrenDelegate, double cacheExtent, int semanticChildCount })
创建一个自定义模型的 GridView。
GridView.extent({Key key, Axis scrollDirection: Axis.vertical, bool reverse: false, ScrollController controller, bool primary, ScrollPhysics physics, bool shrinkWrap: false, EdgeInsetsGeometry padding, @required double maxCrossAxisExtent, double mainAxisSpacing: 0.0, double crossAxisSpacing: 0.0, double childAspectRatio: 1.0, bool addAutomaticKeepAlives: true, bool addRepaintBoundaries: true, bool addSemanticIndexes: true, List
相当于指定第一种构造方法的 gridDelegate 为 SliverGridDelegateWithMaxCrossAxisExtent。
gridDelegate:构造 GridView 的委托者,GridView.count 就相当于指定 gridDelegate 为 SliverGridDelegateWithFixedCrossAxisCount,GridView.extent 就相当于指定 gridDelegate 为 SliverGridDelegateWithMaxCrossAxisExtent,它们相当于对普通构造方法的一种封装。它的值是一个 SliverGridDelegate 对象,参考 2.1 SliverGridDelegate。
cacheExtent:同 ListView,预加载的区域。
controller:同 ListView,滑动监听,值为一个 ScrollController 对象,这个属性应该可以用来做下拉刷新和上垃加载,后面详细研究。
padding:同 ListView,整个 GridView 的内间距。
physics:同 ListView,设置 GridView 如何响应用户的滑动行为,值为一个 ScrollPhysics 对象,它的实现类常用的有:
AlwaysScrollableScrollPhysics:总是可以滑动。
NeverScrollableScrollPhysics:禁止滚动。
BouncingScrollPhysics:内容超过一屏,上拉有回弹效果。
ClampingScrollPhysics:包裹内容,不会有回弹,感觉跟 AlwaysScrollableScrollPhysics 差不多。
reverse:Item 的顺序是否反转,若为 true 则反转,这个翻转只是行翻转,即第一行变成最后一行,但是每一行中的子组件还是从左往右摆放的,用到该属性的开发情景较少。
scrollDirection:GirdView 的方向,为 Axis.vertical 表示纵向,为 Axis.horizontal 表示横向,横向的话 CrossAxis 和 MainAxis 表示的轴也会调换,为 Axis.Horizontal 的情况也较少。
semanticChildCount:不太清楚。
shrinkWrap:不太清楚。
children:子组件,不用多说。
下面是一个设置了上述部分属性的 Demo:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
List imgUrlList = new List();
imgUrlList.add("assets/images/a.jpg");
imgUrlList.add("assets/images/b.jpg");
imgUrlList.add("assets/images/c.jpg");
imgUrlList.add("assets/images/d.jpg");
imgUrlList.add("assets/images/e.jpg");
imgUrlList.add("assets/images/f.jpg");
imgUrlList.add("assets/images/g.jpg");
imgUrlList.add("assets/images/h.jpg");
imgUrlList.add("assets/images/i.jpg");
imgUrlList.add("assets/images/j.jpg");
imgUrlList.add("assets/images/k.jpg");
imgUrlList.add("assets/images/l.jpg");
imgUrlList.add("assets/images/m.jpg");
return MaterialApp(
//是否显示 debug 标签
debugShowCheckedModeBanner: false,
title: "GridView",
home: Scaffold(
appBar: AppBar(
title: Text("GridView"),
),
body: Container(
child: MyGridView(imgUrlList),
),
),
);
}
}
class MyGridView extends StatelessWidget {
List imgUrlList;
MyGridView(this.imgUrlList);
@override
Widget build(BuildContext context) {
List widgetList = new List();
for (int i = 0; i < imgUrlList.length; i++) {
widgetList.add(MyImage(imgUrlList.elementAt(i)));
}
return GridView(
//构造 GridView 的委托者,GridView.count 就相当于指定 gridDelegate 为 SliverGridDelegateWithFixedCrossAxisCount,
//GridView.extent 就相当于指定 gridDelegate 为 SliverGridDelegateWithMaxCrossAxisExtent,它们相当于对普通构造方法的一种封装
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
//必传参数,Cross 轴(在 GridView 中通常是横轴,即每一行)子组件个数
crossAxisCount: 3,
//子组件宽高比,如 2 表示宽:高=2:1,如 0.5 表示宽:高=0.5:1=1:2,简单来说就是值大于 1 就会宽大于高,小于 1 就会宽小于高
childAspectRatio: 0.8,
//Cross 轴子组件的间隔,一行中第一个子组件左边不会添加间隔,最后一个子组件右边不会添加间隔,这一点很棒
crossAxisSpacing: 3,
//Main 轴(在 GridView 中通常是纵轴,即每一列)子组件间隔,也就是每一行之间的间隔,同样第一行的上边和最后一行的下边不会添加间隔
mainAxisSpacing: 3,
)
// SliverGridDelegateWithMaxCrossAxisExtent(
// //必传参数,Cross 轴(在 GridView 中通常是横轴,即每一行)子组件最大宽度,会根据该值来决定一行摆放几个子组件
// maxCrossAxisExtent: 130)
,
//预加载区域
cacheExtent: 0,
//滑动监听,值为一个 ScrollController 对象,同 ListView
// controller:,
//内边距
padding: EdgeInsets.all(10),
//设置 GridView 如何响应用户的滑动行为,值为一个 ScrollPhysics 对象,它的实现类常用的有:
//AlwaysScrollableScrollPhysics:总是可以滑动
//NeverScrollableScrollPhysics:禁止滚动
//BouncingScrollPhysics:内容超过一屏,上拉有回弹效果
//ClampingScrollPhysics:包裹内容,不会有回弹,感觉跟 AlwaysScrollableScrollPhysics 差不多
physics: new BouncingScrollPhysics(),
//Item 的顺序是否反转,若为 true 则反转,这个翻转只是行翻转,即第一行变成最后一行,但是每一行中的子组件还是从左往右摆放的
// reverse: true,
//GirdView 的方向,为 Axis.vertical 表示纵向,为 Axis.horizontal 表示横向,横向的话 CrossAxis 和 MainAxis 表示的轴也会调换
scrollDirection: Axis.vertical,
//不太清楚
// semanticChildCount: ,
//不太清楚
// shrinkWrap: ,
//子组件
children: widgetList,
);
}
}
class MyImage extends StatelessWidget {
String imgUrl;
MyImage(this.imgUrl);
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
child: Image(
image: AssetImage(imgUrl),
width: 300,
height: 300,
fit: BoxFit.cover,
),
);
}
}
运行效果如下:
GridView 其他的构造方法就不做演示了,它的基本用法跟 ListView 差不多,用到的时候稍微研究一下就好。
构造 GridView 的委托者,它有两个实现类:
该委托者通常用于每一行的子组件个数固定的情况,它可以指定如下几个属性:
crossAxisCount:必传参数,Cross 轴(在 GridView 中通常是横轴,即每一行)子组件个数。
childAspectRatio:子组件宽高比,如 2 表示宽:高=2:1,如 0.5 表示宽:高=0.5:1=1:2,简单来说就是值大于 1 就会宽大于高,小于 1 就会宽小于高。
crossAxisSpacing:Cross 轴子组件的间隔,一行中第一个子组件左边不会添加间隔,最后一个子组件右边不会添加间隔,这一点很棒。
mainAxisSpacing:Main 轴(在 GridView 中通常是纵轴,即每一列)子组件间隔,也就是每一行之间的间隔,同样第一行的上边和最后一行的下边不会添加间隔。
maxCrossAxisExtent:必传参数,Cross 轴(在 GridView 中通常是横轴,即每一行)子组件最大宽度,会根据该值来决定一行摆放几个子组件。
其余属性 childAspectRatio、crossAxisSpacing、mainAxisSpacing 同 SliverGridDelegateWithFixedCrossAxisCount。
GridView 跟 Android 中的 GridView 也差不多,所以感觉还是蛮简单的,而且它本来就跟 ListView 差不多,所以不必太深究。因为自己做 Android 的,所以 Flutter 目前为止学起来还是没有什么麻烦,继续努力。