Flutter GridView

这篇博客探讨了Flutter中的GridView布局,包括GridView.count、GridView.builder和SliverGridDelegateWithMaxCrossAxisExtent的用法。通过实例展示了如何构建网格,并解释了不同写法的特点,特别是宽高比、行列数和屏幕适配的原理。
部署运行你感兴趣的模型镜像

今天,我们来聊聊网格布局GridView。
GridView

构造数据(生成Widgets)


List<String> getDataList() {
    List<String> list = [];
    for (int i = 0; i < 100; i++) {
      list.add(i.toString());
    }
    return list;
  }

  List<Widget> getWidgetList() {
    return getDataList().map((item) => getItemContainer(item)).toList();
  }

  Widget getItemContainer(String item) {
    return Container(
      alignment: Alignment.center,
      child: Text(
        item,
        style: TextStyle(color: Colors.white, fontSize: 20),
      ),
      color: Colors.blue,
    );
  }

GridView有好几种写法,万变不离其宗。我们一个个来看看。

写法一:GridView.count


GridView.count(
      //水平子Widget之间间距
      crossAxisSpacing: 10.0,
      //垂直子Widget之间间距
      mainAxisSpacing: 30.0,
      //GridView内边距
      padding: EdgeInsets.all(10.0),
      //一行的Widget数量
      crossAxisCount: 2,
      //子Widget宽高比例
      childAspectRatio: 2.0,
      //子Widget列表
      children: getWidgetList(),
    );

效果:
GridView.count.gif

对于这种写法,此时单个Widget的宽高已经不起作用了。
在我上面构造数据的那一步中,我并没有指定Container的的宽高,这里我们就将其宽高设置为5,看下效果。


Widget getItemContainer(String item) {
    return Container(
      width: 5.0,
      height: 5.0,
      alignment: Alignment.center,
      child: Text(
        item,
        style: TextStyle(color: Colors.white, fontSize: 20),
      ),
      color: Colors.blue,
    );
  }

指定Container 宽高

可以看出没有效果。因为,我们在这里已经指定了每一行分成几列以及宽高比,还有边距等等。所以,我们后面再指定单个item的宽高,已经无效。

其实GridView跟我之前讲过的ListView,基本类似,都是BoxScrollView的子类。
GridView与ListView比较

GridView与ListView比较

写法二:GridView.builder


 @override
  Widget build(BuildContext context) {
    List<String> datas = getDataList();
    return GridView.builder(
        itemCount: datas.length,
        //SliverGridDelegateWithFixedCrossAxisCount 构建一个横轴固定数量Widget
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          //横轴元素个数
            crossAxisCount: 3,
            //纵轴间距
            mainAxisSpacing: 20.0,
            //横轴间距
            crossAxisSpacing: 10.0,
            //子组件宽高长度比例
            childAspectRatio: 1.0),
        itemBuilder: (BuildContext context, int index) {
          //Widget Function(BuildContext context, int index)
          return getItemContainer(datas[index]);
        });
  }

abstract class SliverGridDelegate gridDelegate用来指定GridView的构建方式,具体实现有两个。
SliverGridDelegate
刚才这里例子,使用的SliverGridDelegateWithFixedCrossAxisCount。下面,我们来使用它的另一个实现SliverGridDelegateWithMaxCrossAxisExtent

写法三:GridView.builder(SliverGridDelegateWithMaxCrossAxisExtent)


GridView.builder(
      itemCount: datas.length,
      itemBuilder: (BuildContext context, int index) {
        return getItemContainer(datas[index]);
      },
      gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
        //单个子Widget的水平最大宽度
        maxCrossAxisExtent: 200,
        //水平单个子Widget之间间距
        mainAxisSpacing: 20.0,
        //垂直单个子Widget之间间距
        crossAxisSpacing: 10.0
      ),
    );

对于SliverGridDelegateWithMaxCrossAxisExtent而言,水平方向元素个数不再固定,其水平个数也就是有几列,由maxCrossAxisExtent和屏幕的宽度以及paddingmainAxisSpacing等决定。

例如:我这里的虚拟机宽度为400,当maxCrossAxisExtent:50时,有8列;当maxCrossAxisExtent:100时,有4列。如下:

maxCrossAxisExtent效果
内容内容
maxCrossAxisExtent:50image.png
maxCrossAxisExtent:100image.png

写法四:


@override
  Widget build(BuildContext context) {
    List<String> datas = getDataList();
    return GridView.custom(
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3, mainAxisSpacing: 10.0, crossAxisSpacing: 20.0, ),
        childrenDelegate: SliverChildBuilderDelegate((context, position) {
          return getItemContainer(datas[position]);
        }, childCount: datas.length));
  }

GridView.custom.gif

这几个参数,上面都讲过了,不再赘述了。

#本文代码地址

您可能感兴趣的与本文相关的镜像

GPT-oss:20b

GPT-oss:20b

图文对话
Gpt-oss

GPT OSS 是OpenAI 推出的重量级开放模型,面向强推理、智能体任务以及多样化开发场景

### FlutterGridView 的基本用法 #### 1. 使用 `GridView.count` 创建固定数量的网格布局 `GridView.count` 是一种简单的实现方式,适用于已知子项总数的情况。以下是基于引用[^1]的一个简单示例: ```dart import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: MyHomePage(), ); } } class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('GridView Count Example')), body: GridView.count( crossAxisCount: 3, // 每行显示三个项目 children: List.generate(9, (index) { return Card( child: Center(child: Text('Item ${index + 1}')), ); }), ), ); } } ``` 此代码展示了如何使用 `crossAxisCount` 来设置每行的列数,并通过 `List.generate` 方法生成固定的子项。 --- #### 2. 动态加载数据:`GridView.builder` 当需要处理大量数据或者动态加载时,推荐使用 `GridView.builder`。这种方式不会一次性渲染所有子项,而是按需懒加载,从而提高性能[^2]。 ```dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Dynamic Grid View', theme: ThemeData(primarySwatch: Colors.green), home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { final List<String> items = List.generate(50, (i) => "Item $i"); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Dynamic GridView Builder')), body: GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2), // 每行列数为2 itemCount: items.length, itemBuilder: (context, index) { return Card( child: Padding( padding: const EdgeInsets.all(8.0), child: Text(items[index]), ), ); }, ), ); } } ``` 在此示例中,`SliverGridDelegateWithFixedCrossAxisCount` 定义了每一行的列数,而 `itemBuilder` 则负责动态构建每个子项的内容。 --- #### 3. 自定义样式与资源加载 如果希望在网格中加载本地图片或其他资源,可以通过 `Image.asset` 或者网络图片的方式完成。以下是一个结合图片和文字的例子[^4]: ```dart import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Custom GridView with Images', theme: ThemeData(primarySwatch: Colors.red), home: MyHomePage(), ); } } class MyHomePage extends StatelessWidget { final List<Map<String, dynamic>> data = [ {'title': 'Apple', 'imagePath': 'assets/images/apple.png'}, {'title': 'Banana', 'imagePath': 'assets/images/banana.png'}, {'title': 'Cherry', 'imagePath': 'assets/images/cherry.png'} ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Custom GridView')), body: GridView.builder( gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(maxCrossAxisExtent: 200), itemCount: data.length, itemBuilder: (context, index) { return Card( elevation: 4, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: Image.asset(data[index]['imagePath'], fit: BoxFit.cover), ), SizedBox(height: 8), Text(data[index]['title']), ], ), ); }, ), ); } } ``` 注意:为了使上述代码正常运行,需要先在项目的 `pubspec.yaml` 文件中声明资源路径。 ```yaml flutter: assets: - assets/images/ ``` --- #### 4. 高级属性解析 除了常见的参数外,还有一些高级选项可以帮助开发者更好地控制行为: - **`scrollDirection`**: 默认垂直滚动 (`Axis.vertical`),也可以改为水平滚动 (`Axis.horizontal`)。 - **`reverse`**: 如果设为 true,则会反转整个列表的方向。 - **`controller`**: 提供对滚动位置的手动控制能力。 - **`physics`**: 控制滚动效果的行为(如禁用手势滑动)。 例如,下面是如何启用水平滚动并添加自定义物理特性的例子: ```dart body: GridView.builder( scrollDirection: Axis.horizontal, physics: BouncingScrollPhysics(), // 添加回弹效果 ... ); ``` --- ### 总结 以上介绍了三种主要的 `GridView` 构建方式及其常见应用场景。无论是静态还是动态的数据源都可以轻松适配到网格布局之中。同时,合理利用其扩展属性能够进一步提升用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值