Flutter GridView 网格控件

2020-09-10 15:47:35 浏览数 (1)

在项目中,有时候会有诸如“日历”展示之类的需求,此时单列表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展示)

代码语言:javascript复制
@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展示)

代码语言:javascript复制
    @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.extentSliverGridDelegateWithMaxCrossAxisExtent的另一种代码表现形式(大概是因为名字太长了),它们具有相同的功能。

用法:

代码语言: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、使用步骤:
  1. 导入flutter_staggered_grid_view库。

pubspec.yaml文件中导入如下代码:

代码语言:javascript复制
dependencies:
  # 瀑布流
  flutter_staggered_grid_view: ^0.2.7
  1. 导入包到代码文件
代码语言:javascript复制
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
  1. 使用
代码语言:javascript复制
        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的高度进行调整。

0 人点赞