Flutter网格控件GridView

Flutter GridView

网格布局在移动开发中也经常使用,Flutter 给我们提供了GridView供我们使用,下面我们来看看GridView的使用方法

继承关系

在这里插入图片描述
构造方法

  GridView({
    Key key,
    Axis scrollDirection = Axis.vertical, 
    bool reverse = false,  
    ScrollController controller,
    bool primary,
    ScrollPhysics physics,
    bool shrinkWrap = false, 
    EdgeInsetsGeometry padding,  
    @required this.gridDelegate, 
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    double cacheExtent,
    List<Widget> children = const <Widget>[],
    int semanticChildCount,
  })

属性

属性值类型说明
scrollDirectionAxis设置滚动的方向,horizontal(水平)或vertical(垂直)
reversebool是否翻转
controllerScrollController用来控制滚动位置及监听滚动事件
shrinkWrapbool是否根据子widget的总长度来设置GridView的长度
paddingEdgeInsetsGeometry间距
gridDelegateSliverGridDelegate控制子Widget如何进行布局
childrenList子控件

常用属性比较易懂,这里我们主要看一下gridDelegate

gridDelegate
该属性接收一个SliverGridDelegate类型的值,主要是用来控制子Widget如何进行布局。
在这里插入图片描述
他有如下两个实现类
SliverGridDelegateWithMaxCrossAxisExtent和SliverGridDelegateWithFixedCrossAxisCount

SliverGridDelegateWithMaxCrossAxisExtent
创建一个具有交叉轴最大值的一个网格布局,对主轴和交叉轴不太明白的可以看Flutter主轴交叉轴详解

构造方法:

  const SliverGridDelegateWithMaxCrossAxisExtent({
    @required this.maxCrossAxisExtent, //子控件的最大宽度,实际宽度是根据交叉轴的值进行平分,也就是说最大宽度并不一定是实际宽度,很有可能子控件的实际宽度要小于设置的最大宽度
    this.mainAxisSpacing = 0.0, //主轴之间的间距
    this.crossAxisSpacing = 0.0,//交叉轴之间的间距
    this.childAspectRatio = 1.0,//子控件的宽高比
  }

下面我们来简单用一用

GridView(
      scrollDirection: Axis.vertical,
      gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
        maxCrossAxisExtent: 100, //子控件最大宽度为100
        childAspectRatio: 0.5,//宽高比为1:2
        crossAxisSpacing: 10,
        mainAxisSpacing: 10,
      ),
      padding: EdgeInsets.all(10),
      children: List.generate(
        20,
        (index) {
          return Box(index + 1);
        },
      ),
    );

显示效果:
在这里插入图片描述
看了效果图我们可能会有疑问,我最大宽度设置的是110,那子控件为什么是4个呢

首先我们先来看子控件的个数:

子控件的个数实际上就是交叉轴的最大宽度除以我们设置的最大值得出的值,如果该值为整数,那个该值就是子控件的个数,如果不是整数,那么就舍掉小数点后面的值加上一后就是子控件的个数

举个例子:

假如交叉轴最大值为360,我们设置的最大值为89,那么子控件的个数就是5,如果我们设置的最大值为90,那么子控件的个数就是4,如果我们设置的最大值为91,那么子控件的个数也是4

如果我们想明确的指定子控件的个数,我们可以这样写:

maxCrossAxisExtent: MediaQuery.of(context).size.width/4,

MediaQuery.of(context).size.width就是屏幕的宽度,除以4,就是子控件的最大值,这样一来我们就可以确定要显示的子控件的个数了

例如,我们更改一下滚动方向为横向滚动,此时交叉轴为垂直方向,那么最大值就是屏幕的高度。我们想让子控件个数为5,就可以这么写:

   maxCrossAxisExtent: MediaQuery.of(context).size.height/5,

示例代码

GridView(
      scrollDirection: Axis.horizontal,
      gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
        maxCrossAxisExtent: MediaQuery.of(context).size.height/5,
        mainAxisSpacing: 10,
        crossAxisSpacing: 10,
      ),
      children: List.generate(
        20,
        (index) {
          return Box(index + 1);
        },
      ),
    );

在这里插入图片描述

SliverGridDelegateWithFixedCrossAxisCount
理解了上面那个这个就很好理解了,就是设置交叉轴上子控件的个数

构造方法:

  const SliverGridDelegateWithFixedCrossAxisCount({
    @required this.crossAxisCount,  //交叉轴上子控件的个数
    this.mainAxisSpacing = 0.0,
    this.crossAxisSpacing = 0.0,
    this.childAspectRatio = 1.0,
  }) 

示例代码:

GridView(
      scrollDirection: Axis.horizontal,
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 6,
        mainAxisSpacing: 10,
        crossAxisSpacing: 10,
      ),
      children: List.generate(
        20,
        (index) {
          return Box(index + 1);
        },
      ),
    );

效果图:
在这里插入图片描述


除了传统的构造方法外,GridView给我们提供更加方便的方法供我们使用

GridView.count

没什么好说的,跟上面的SliverGridDelegateWithFixedCrossAxisCount雷同
示例代码:

GridView.count(
      padding: EdgeInsets.all(10),
      crossAxisSpacing: 10,
      crossAxisCount: 3,
      mainAxisSpacing: 10,
      children: List.generate(
        20,
        (index) {
          return Box(index + 1);
        },
      ),
    );

在这里插入图片描述

GridView.extent

跟SliverGridDelegateWithMaxCrossAxisExtent类似

GridView.extent(
      scrollDirection: Axis.horizontal,
      maxCrossAxisExtent: MediaQuery.of(context).size.height/9,
      children: List.generate(
        20,
        (index) {
          return Box(index + 1);
        },
      ),
    );

在这里插入图片描述

Flutter GridView异步加载/加载更多(GridView.builder)

跟构造方法使用方式差不多,主要是用来做异步数据加载的,前面几种方式都是在数据确定的情况下,实际上,我们的数据基本上都是从网络上获取的,有分页获取的需求,这个时候就用到GridView.builder了。

首先看看源码:

  GridView.builder({
    Key key,
    Axis scrollDirection = Axis.vertical,
    bool reverse = false,
    ScrollController controller,
    bool primary,
    ScrollPhysics physics,
    bool shrinkWrap = false,
    EdgeInsetsGeometry padding,
    @required this.gridDelegate,
    @required IndexedWidgetBuilder itemBuilder,
    int itemCount,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    double cacheExtent,
    int semanticChildCount,
  })

属性跟构造方法中的属性差不多,我们主要来看看itemCountitemBuilder

itemCount表示列表的数量,一般都是集合的长度
itemBuilder是列表项构造器,返回一个Widget

示例代码:

import 'package:flutter/material.dart';

/*
* 
* 网格布局
* */
class GridViewWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _GridViewVBuilder();
  }
}

class _GridViewVBuilder extends State<GridViewWidget> {
  List<int> indexs = List.generate(100, (index) {
    return index;
  });

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate:
          SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 5),
      itemCount: indexs.length,
      itemBuilder: (context, index) {

        /*当数据加载完毕时 追加数据*/
        if (index == indexs.length - 1 && indexs.length < 200) {
          _addIndex();
        }

        return Text(
          "$index",
          textAlign: TextAlign.center,
          style: TextStyle(
            color: Colors.red,
            fontSize: 20,
          ),
        );
      },
    );
  }

  void _addIndex() {

    /*这里要延时加载  否则会抱The widget on which setState() or markNeedsBuild() was called was:错误*/
    Future.delayed(Duration(milliseconds: 200)).then((e) {
      setState(() {
        indexs.add(indexs.length + 1);
      });
    });
  }
}


效果图如下:

在这里插入图片描述

好了,GridView基本用法大概就是这样。


如果你觉得本文对你有帮助,麻烦动动手指顶一下,算是对本文的一个认可。也可以关注我的 Flutter 博客专栏,我会不定期的更新,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喻志强(Xeon)

码字不易,鼓励随意。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值