Flutter 基础组件之 GridView

GridView 虽不及 ListView 用得多,但是 ListView 如果是纵向滚动的,那么在一行上一般算作一个 Item,如果是横向滚动,那么一在一列上一般算作一个 Item,如果需要一行展示多个 Item 但是又需要纵向滚动的话,就需要 GridView 了,在一些特定的情景,如展示图片的时候效果比 ListView 更棒,所以这也是个很重要的组件。

由于 GridView 很多属性跟 ListView 差不多,所有部分属性的用法可以参考 Fluutter 基础组件之 ListView

 

1 构造方法

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 children: const [], int semanticChildCount })

构造一个 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 children: const [], int semanticChildCount })

相当于指定第一种构造方法的 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 children: const [], int semanticChildCount })

相当于指定第一种构造方法的 gridDelegate 为 SliverGridDelegateWithMaxCrossAxisExtent。

 

2 常用属性

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 差不多,用到的时候稍微研究一下就好。

 

2.1 SliverGridDelegate

构造 GridView 的委托者,它有两个实现类:

2.1.1 SliverGridDelegateWithFixedCrossAxisCount

该委托者通常用于每一行的子组件个数固定的情况,它可以指定如下几个属性:

crossAxisCount:必传参数,Cross 轴(在 GridView 中通常是横轴,即每一行)子组件个数。

childAspectRatio:子组件宽高比,如 2 表示宽:高=2:1,如 0.5 表示宽:高=0.5:1=1:2,简单来说就是值大于 1 就会宽大于高,小于 1 就会宽小于高。

crossAxisSpacing:Cross 轴子组件的间隔,一行中第一个子组件左边不会添加间隔,最后一个子组件右边不会添加间隔,这一点很棒。

mainAxisSpacing:Main 轴(在 GridView 中通常是纵轴,即每一列)子组件间隔,也就是每一行之间的间隔,同样第一行的上边和最后一行的下边不会添加间隔。

 

2.1.2 SliverGridDelegateWithMaxCrossAxisExtent

maxCrossAxisExtent:必传参数,Cross 轴(在 GridView 中通常是横轴,即每一行)子组件最大宽度,会根据该值来决定一行摆放几个子组件。

其余属性 childAspectRatio、crossAxisSpacing、mainAxisSpacing 同 SliverGridDelegateWithFixedCrossAxisCount。

 

3 总结

GridView 跟 Android 中的 GridView 也差不多,所以感觉还是蛮简单的,而且它本来就跟 ListView 差不多,所以不必太深究。因为自己做 Android 的,所以 Flutter 目前为止学起来还是没有什么麻烦,继续努力。

你可能感兴趣的:(前端,Flutter)