42、Flutter之GridView组件详解

2023-11-01

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,
    double? cacheExtent, 
    List<Widget> children = const <Widget>[],
    ...
  })

我们可以看到,GridViewListView的大多数参数都是相同的,它们的含义也都相同的,如有疑惑读者可以翻阅ListView一节,在此不再赘述。我们唯一需要关注的是gridDelegate参数,类型是SliverGridDelegate,它的作用是控制GridView子组件如何排列(layout)。

SliverGridDelegate是一个抽象类,定义了GridView Layout相关接口,子类需要通过实现它们来实现具体的布局算法。Flutter中提供了两个SliverGridDelegate的子类SliverGridDelegateWithFixedCrossAxisCountSliverGridDelegateWithMaxCrossAxisExtent,我们可以直接使用,下面我们分别来介绍一下它们。

SliverGridDelegateWithFixedCrossAxisCount

该子类实现了一个横轴为固定数量子元素的layout算法,其构造函数为:

SliverGridDelegateWithFixedCrossAxisCount({
  @required double crossAxisCount, 
  double mainAxisSpacing = 0.0,
  double crossAxisSpacing = 0.0,
  double childAspectRatio = 1.0,
})
  • crossAxisCount:横轴子元素的数量。此属性值确定后子元素在横轴的长度就确定了,即ViewPort横轴长度除以crossAxisCount的商。
  • mainAxisSpacing:主轴方向的间距。
  • crossAxisSpacing:横轴方向子元素的间距。
  • childAspectRatio:子元素在横轴长度和主轴长度的比例。由于crossAxisCount指定后,子元素横轴长度就确定了,然后通过此参数值就可以确定子元素在主轴的长度。

可以发现,子元素的大小是通过crossAxisCountchildAspectRatio两个参数共同决定的。注意,这里的子元素指的是子组件的最大显示空间,注意确保子组件的实际大小不要超出子元素的空间。

下面看一个例子:

GridView(
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3,//横轴三个子widget
          childAspectRatio: 1.0,//子widget宽高比例
        ),
      children: const [
        Icon(Icons.ac_unit),
        Icon(Icons.airport_shuttle),
        Icon(Icons.all_inclusive),
        Icon(Icons.beach_access),
        Icon(Icons.cake),
        Icon(Icons.free_breakfast)
      ],
    )

 

GridView.count

GridView.count构造函数内部使用了SliverGridDelegateWithFixedCrossAxisCount,我们通过它可以快速的创建横轴固定数量子元素的GridView,上面的示例代码等价于:

GridView.count(
      crossAxisCount: 3,
      childAspectRatio: 1.0,
      children: const [
        Icon(Icons.ac_unit),
        Icon(Icons.airport_shuttle),
        Icon(Icons.all_inclusive),
        Icon(Icons.beach_access),
        Icon(Icons.cake),
        Icon(Icons.free_breakfast),
      ],
    )

SliverGridDelegateWithMaxCrossAxisExtent

该子类实现了一个横轴子元素为固定最大长度的layout算法,其构造函数为:

SliverGridDelegateWithMaxCrossAxisExtent({
  double maxCrossAxisExtent,
  double mainAxisSpacing = 0.0,
  double crossAxisSpacing = 0.0,
  double childAspectRatio = 1.0,
})

 maxCrossAxisExtent为子元素在横轴上的最大长度,之所以是“最大”长度,是因为横轴方向每个子元素的长度仍然是等分的,举个例子,如果ViewPort的横轴长度是450,那么当maxCrossAxisExtent的值在区间[450/4,450/3)内的话,子元素最终实际长度都为112.5,而childAspectRatio所指的子元素横轴和主轴的长度比为最终的长度比。其它参数和SliverGridDelegateWithFixedCrossAxisCount相同。

下面我们看一个例子:

GridView(
  padding: EdgeInsets.zero,
  gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
      maxCrossAxisExtent: 120.0,
      childAspectRatio: 2.0 //宽高比为2
  ),
  children: <Widget>[
    Icon(Icons.ac_unit),
    Icon(Icons.airport_shuttle),
    Icon(Icons.all_inclusive),
    Icon(Icons.beach_access),
    Icon(Icons.cake),
    Icon(Icons.free_breakfast),
  ],
);

 

GridView.extent

GridView.extent构造函数内部使用了SliverGridDelegateWithMaxCrossAxisExtent,我们通过它可以快速的创建纵轴子元素为固定最大长度的的GridView,上面的示例代码等价于:

GridView.extent(
   maxCrossAxisExtent: 120.0,
   childAspectRatio: 2.0,
   children: <Widget>[
     Icon(Icons.ac_unit),
     Icon(Icons.airport_shuttle),
     Icon(Icons.all_inclusive),
     Icon(Icons.beach_access),
     Icon(Icons.cake),
     Icon(Icons.free_breakfast),
   ],
 );

GridView.builder

上面我们介绍的GridView都需要一个widget数组作为其子元素,这些方式都会提前将所有子widget都构建好,所以只适用于子widget数量比较少时,当子widget比较多时,我们可以通过GridView.builder来动态创建子widget。GridView.builder 必须指定的参数有两个:

GridView.builder(
 ...
 required SliverGridDelegate gridDelegate, 
 required IndexedWidgetBuilder itemBuilder,
)

其中itemBuilder为子widget构建器。

假设我们需要从一个异步数据源(如网络)分批获取一些Icon,然后用GridView来展示:

import 'package:demo202112/utils/common_appbar.dart';
import 'package:flutter/material.dart';

/// @Author wywinstonwy
/// @Date 2022/1/21 8:48 上午
/// @Description: 

class MyGridViewPage extends StatefulWidget {
  const MyGridViewPage({Key? key}) : super(key: key);

  @override
  _MyGridViewPageState createState() => _MyGridViewPageState();
}

class _MyGridViewPageState extends State<MyGridViewPage> {
  List<IconData> _icons = []; //保存Icon数据

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _retrieveIcons();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: getAppBar('GridView'),
      body: _buildGridBuilderView(),

    );
  }
  _buildGridView(){
    return GridView(
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3,//横轴三个子widget
          childAspectRatio: 1.0,//子widget宽高比例
        ),
      children: const [
        Icon(Icons.ac_unit),
        Icon(Icons.airport_shuttle),
        Icon(Icons.all_inclusive),
        Icon(Icons.beach_access),
        Icon(Icons.cake),
        Icon(Icons.free_breakfast)
      ],
    );
  }
  _buildGridCountView(){
    return GridView.count(
      crossAxisCount: 3,
      childAspectRatio: 1.0,
      children: const [
        Icon(Icons.ac_unit),
        Icon(Icons.airport_shuttle),
        Icon(Icons.all_inclusive),
        Icon(Icons.beach_access),
        Icon(Icons.cake),
        Icon(Icons.free_breakfast),
      ],
    );
  }

  _buildGridView1(){
    return GridView(
      padding: EdgeInsets.zero,
      gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
          maxCrossAxisExtent: 120.0,
          childAspectRatio: 2.0 //宽高比为2
      ),
      children: const <Widget>[
        Icon(Icons.ac_unit),
        Icon(Icons.airport_shuttle),
        Icon(Icons.all_inclusive),
        Icon(Icons.beach_access),
        Icon(Icons.cake),
        Icon(Icons.free_breakfast),
      ],
    );

  }
  _buildGridBuilderView(){
    return GridView.builder(
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3,
          childAspectRatio: 1.0
        ),
        itemCount: _icons.length,
        itemBuilder: (context,index){
          //如果显示到最后一个并且Icon总数小于200时继续获取数据
          if(index == _icons.length-1 && _icons.length<200){
              _retrieveIcons();
          }
          return Icon(_icons[index]);
        });
  }
  _retrieveIcons(){
    Future.delayed(Duration(milliseconds: 200)).then((value){
      setState(() {
        _icons.addAll([
          Icons.ac_unit,
          Icons.airport_shuttle,
          Icons.all_inclusive,
          Icons.beach_access,
          Icons.cake,
          Icons.free_breakfast,
        ]);
      });
    });
  }
}
  • _retrieveIcons():在此方法中我们通过Future.delayed来模拟从异步数据源获取数据,每次获取数据需要200毫秒,获取成功后将新数据添加到_icons,然后调用setState重新构建。
  • 在 itemBuilder 中,如果显示到最后一个时,判断是否需要继续获取数据,然后返回一个Icon。

效果:

  demo完整代码:flutter_demo: flutter组件测试学习demo

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

42、Flutter之GridView组件详解 的相关文章

  • Flutter - 将未来列表传递给 SearchDelegate

    我一直在关注 Flutter Search 教程 我一直在尝试使用从未来列表派生的列表来实现相同的功能 其中数据来自 api 在本例中是 Aqueduct 服务器 目前我的屏幕列出了 api 中的所有联系人 我现在想搜索该联系人列表 我假设
  • Android Studio 3.2.1 升级后构建错误

    我正在从 Udacity 构建一个示例项目 到目前为止 一切正常 但升级到 Android Studio 3 2 1 后 我遇到了下面的构建错误 摇篮版本 4 6 项目链接 https github com udacity ud851 Su
  • 在 Unity 4.6 中构建的游戏中,插页式广告未在实时 Android 设备上显示

    我使用的是Unity版本 gt 4 6 0Admob版本 gt Google 移动广告 Unity 插件 v3 1 3 https github com googleads googleads mobile unity releases t
  • 如何修复C风格的for语句?

    什么是正确的修复方法C 风格的 for 语句对于下面发布的代码 目前我正在交战 C 风格的 for 语句已弃用 并将在将来删除 斯威夫特的版本 var ifaddr UnsafeMutablePointer
  • 如何在 flutter/dart 中使用设定大小的自定义字体?

    我正在尝试使用color fontWeight and fontFamily with style style copyWith 我尝试使用的自定义字体是Vonique 我已经将它像这样导入到pubspec yaml fonts famil
  • CNContact 添加新的联系人问题

    我在通过以下方式添加联系人时遇到问题联系框架 我使用的是装有 iOS 12 1 2 的 iPhone 5s 设备 我添加联系人的代码如下 let saveRequest CNSaveRequest saveRequest add self
  • 使用prefersLargeTitles 和 UITableView 平滑滚动

    我在使用时遇到了滚动问题prefersLargeTitles并添加了UITableView 如果我设置prefersLargeTitles在导航控制器中 其根是UITableViewController一切都很好 导航大标题的滚动方式与我们
  • 如何更改 UISwitch 关闭状态的默认颜色?

    我想更改 UISwitch 中 onTintColor 的颜色以表示关闭状态 切换位于表格视图中 并且以编程方式进行切换 settingsSwitch setBackgroundColor UIColor whiteColor settin
  • Facebook 登录按钮:应用自定义样式

    我在使用新的 Facebook android sdk 4 时遇到了一个奇怪的问题 对于旧的 sdk 版本 我使用的是
  • 如何在运行时添加TextView?

    如何在运行时向布局添加新的 TextView 是否可以 完整的解决方案 View parent parent view where to add ViewGroup layout new LinearLayout context layou
  • 为 Android 编译时显示 FFMPEG 错误

    我正在尝试将 ffmpeg 添加到我的 android 项目中 我使用的是 ubuntu 14 04 操作系统 我正在关注此链接 Link https software intel com en us android blogs 2013
  • 在选择项目之前设置微调器的文本

    我有一个包含三个项目的微调器 我使用 XML 字符串数组资源来为其提供数据 当您打开活动时 微调器通常会显示数组列表中的第一项 我想更改它并在选择项目之前在微调器中显示文本 选择一个 我怎样才能做到这一点 您可以通过以下两种方式之一进行操作
  • android.R.layout.simple_list_item_1是什么?

    在我看到的所有示例中 他们在创建 ArrayAdapter 时仅使用 android R layout simple list item 1 android R layout simple list item 1是什么 它只是一个名为sim
  • 应用程序启动时显示徽标几秒钟

    我想在应用程序启动并且菜单可见之前显示徽标几秒钟 当它消失时我也想使用一些 我应该创建一个新活动吗 我可以在布局中设置它吗 为包含您的徽标的初始屏幕定义一个布局 然后将此代码添加到您的活动中 public void onCreate Bun
  • 从应用程序打开无线设置

    我想直接从我的应用程序打开 设置 gt 无线和网络 我怎样才能做到这一点 尝试这个 startActivity new Intent android provider Settings ACTION WIRELESS SETTINGS 或者
  • 如何在Android AsyncTask中显示Toast?

    我正在尝试在我的initial background类中显示Toast 扩展为AsyncTask
  • android.media.Ringtone.play() 在播放 28 次后停止工作

    我有一个打开了几个小时的应用程序 并使用后台服务并附加了前台通知 每隔一段时间就会使用以下方式播放声音 try Ringtone r RingtoneManager getRingtone context uri r play catch
  • 在 iOS 中管理和解除多个视图控制器

    我是一名 iPhone 新手程序员 在开发我的第一个游戏 应用程序时 我为自己提出了一个问题 创造了一个问题 我对此进行了研究 并认为我已经看到了答案 但我不明白如何使它们适用于我的应用程序 我有一个游戏 有几个视图控制器 欢迎 玩 高分
  • 找不到图标路径的 Cordova Android 版本

    打字时cordova build android在 DOS 框中 没有构建任何内容 但我看到一条错误消息 错误 源路径不存在 resources android icon drawable hdpi icon png 我已经更新了 Cord
  • Android API 8、10 ContactsContract.Data.HAS_PHONE_NUMBER 没有这样的列

    以下查询在我的设备上运行良好 API 15 它在我运行 API 8 或 API 10 的模拟器中不起作用 这是查询 Cursor contactsCur getContentResolver query ContactsContract D

随机推荐

  • 电脑主板线路连接图解_台式机电源线接法图解(电脑主板接线图解高清

    对于组装一台电脑 主板上的跳线是最让小白装机用户头疼的事情 但其实具体跳线插法 在机箱连接的跳线接口上以及主板跳线插座上都有详细标注 我们只需要在主板上找到对应插座 插上去就好了 那么机箱上的跳线接在主板那些位置 下面精装之家分享一下台式电
  • springBoot框架简介入门教程(快速学习版)

    文章目录 回顾spring 优点 缺点 SpringBoot概述 SpringBoot特点 SpringBoot 的核心功能 SpringBoot自动配置 SpringBoot开发环境构建 SpringBoot配置文件 SpringBoot
  • 【P2P租车】宝驾租车:学大创始人李如彬再创业

    转自 http www cyzone cn a 20140708 260116 html 月底 上线仅一周的私家车共享平台宝驾租车获得500万美元天使投资 这是李如彬第二次创业 李如彬自己有20多辆车 平时大多闲置 这让他看到了机会 宝驾租
  • mysql 添加用户

    mysql 添加用户 1 旧版本的mysql添加新用户 INSERT INTO mysql user host user password select priv insert priv update priv VALUES localho
  • 分布式事务6种解决方案(超详细)

    文章目录 分布式事务六种解决方案 前言 ACID 分布式事务 2PC 二阶段提交 同步阻塞协议 准备阶段 提交阶段 协调者故障分析 协调者是一个单点 存在单点故障问题 3PC 三阶段提交 准备阶段 预提交阶段 提交阶段 参与者超时机制 总结
  • 极海MCU---keil5手动添加Pack

    下载pack文件 进入极海半导体官网 技术支持 点进去下拉 找到软件支持 找到对应的芯片 我使用的是APM32F1XX 软件支持中包括pack和SDK SDK中有库文件和一些例程 开发时会用到 都下载下来 keil5中安装pack 打开ke
  • IDEA无法创建目录

    在WEB INF目录下添加新目录 右键找不到new directory选项 可能是因为设置junit test目录导致 在项目上右键 选择 Make Directory as 之后再选择 unmarke开头的那个选项 下图中是选择过后的 已
  • luckysheet的使用——10.页面缩放报错问题

    在使用luckysheet的项目 切换到其他页面后 对该页面进行缩放的操作时 会触发luckysheet的resize操作 此时因为当前页面并非是luckysheet的调用页面 页面就会报错无法使用 需要对源码进行修改 阻止该方法的调用 1
  • NAT 技术详解

    一 什么是NAT 为什么要使用NAT NAT是将私有地址转换为合法IP地址的技术 通俗的讲就是将内网与内网通信时怎么将内网私有IP地址转换为可在网络中传播的合法IP地址 NAT的出现完美地解决了lP地址不足的问题 而且还能够有效地避免来自网
  • android如果将recyclerView嵌套进NestedScrollView中,可能导致加载更多一直执行

    今天在使用BaseQuickAdapter对RecyclerView进行绑定的时候 支持加载更多 却发现一直自动进行加载更多 最后发现问题是因为在NestedScrollView中的缘故 还不知为什么
  • Gradio学习笔记--Gradio基本用法和简单案例

    目录 1 配置Gradio 2 Hello World案例 2 1 基本使用 2 2 进阶使用 3 图像案例 3 常用类 Interface 和 Blocks 1 配置Gradio 使用 pip 安装 Gradio pip install
  • Feedsky 上 csdn blog 订阅数排名 (zz)

    1114356 programmer editor http blog csdn net programmer editorhttp feeds feedsky com csdn net programmer editor 23897 po
  • Ubuntu子系统下ssh安装、开启等

    查看win系统盘符 ls 加粗部分为代码 yt PC 20200902BXWS cd mnt yt PC 20200902BXWS mnt ls 因为电脑上有四个盘 外加一个虚拟环境wsl 在这里插入代码片 查看linux 目录 才是根目录
  • 出现了一个意外,不能完成你在设置中所要求的更改

    今天叫了师傅来装宽带 在配置IP地址的时候出现了这样的情况 本来我里面是有以前设置的IP地址和DNS服务器地址 现在要更改成自动获取 结果总是弹出这样的错误信息来 有点烦 师傅忙活了半天 也没能搞定 正巧到了饭点 他叫我先自己弄弄 他先回去
  • 嘉立创投板笔记-Altum Designer机械层对板子形状的影响

    本次采用最简单的zip下单 操作部分记录如下 板子边框层用嘉立创建议的机械层1 mechanical 1 虽然 3D图仅供参考 具体以实物为准 但是嘉立创自家的3D解析想必也能反映出一定的形状识别逻辑的 注意 本笔记仅供参考 具体说法以嘉立
  • facenet代码注释

    facenet识别中的embedding代码块 import tensorflow as tf import numpy as np import sys import os import copy sys path append alig
  • 原型绘制提效技巧分享

    不管是前台PM还是后台PM 在工作中或多或少都要进行原型设计 原型可以说是产品 开发 测试之间进行交流沟通最重要的文档之一 那么怎么把原型画得又快又好呢 从设计流程上看 原型设计节点包括但不限于梳理需求大纲 规划页面结构 完善信息结构 绘制
  • 存储器了解

    1 sdio 之前弄过一个wifi模块 在stm32单片机上 基于sdio开发的 SDIO Wifi模块是基于SDIO接口的符合wifi无线网络标准的嵌入式模块 内置无线网络协议IEEE802 11协议栈以及TCP IP协议栈 能够实现用户
  • vue中根据某一个值的改变而动态改变样式

    最近有一个需求 动态改变宽度 缩小就变420px 放大宽度就应该占满整个屏幕 第一步 在div那里定义一个ref的值 第二步 计算屏幕的宽度 第三步 监听数的改变 从而改变样式 4 完美 收工
  • 42、Flutter之GridView组件详解

    GridView GridView可以构建一个二维网格列表 其默认构造函数定义如下 GridView Key key Axis scrollDirection Axis vertical bool reverse false ScrollC