Flutter那些事-GridView

一、GridView简介

GridView是一个可滚动的二维网格布局组件,用于展示多行多列的列表项。

二、GridView的创建方式

1. GridView.count - 固定列数

dart 复制代码
import 'package:flutter/material.dart';

void main(List<String> args) {
  runApp(MainPage());
}

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

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

class _MainPageState extends State<MainPage> {
  ScrollController _controller = ScrollController();
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("GridView"),
        ),
        body:GridView.count(        
          // scrollDirection: Axis.vertical,   // 滚动方向  垂直方向
          scrollDirection: Axis.horizontal,   // 滚动方向  水平方向
          padding: EdgeInsets.all(10),  // 内边距
          crossAxisCount: 5,  // 列数
          mainAxisSpacing: 10,  // 行间距
          crossAxisSpacing: 10,   // 列间距
          childAspectRatio: 1,  // 宽高比
          children: List.generate(100, (int index){
            return Container(
              color: Colors.red,
              child: Text("第${index+1}个",
                style: TextStyle(color: Colors.white,fontSize: 20),
              ),
            );
          }),
        )
      ),
    );
  }
}

2. GridView.extent - 最大宽度

dart 复制代码
import 'package:flutter/material.dart';

void main(List<String> args) {
  runApp(MainPage());
}

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

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

class _MainPageState extends State<MainPage> {
  ScrollController _controller = ScrollController();
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("GridView"),
        ),
        body:GridView.extent(
          maxCrossAxisExtent: 100,  // 每个子项的最大宽度
          mainAxisSpacing: 20,  // 行间距
          crossAxisSpacing: 20,   // 列间距
          childAspectRatio: 1,  // 长宽比
          padding: EdgeInsets.all(10),  // 内边距
          children: List.generate(20, (int index){
            return Container(
              color: Colors.amber,
              child: Text("第${index+1}个",
                style: TextStyle(color: Colors.white,fontSize: 20),
              ),
            alignment: Alignment.center,
            );
          }),
        )
      ),
    );
  }
}

3. GridView.builder - 动态构建(性能最优)

dart 复制代码
import 'package:flutter/material.dart';

void main(List<String> args) {
  runApp(MainPage());
}

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

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

class _MainPageState extends State<MainPage> {
  ScrollController _controller = ScrollController();
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("GridView"),
        ),
        body:GridView.builder(
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 5,
            mainAxisSpacing: 10,
            crossAxisSpacing: 10,
            childAspectRatio: 1,
          ), 
          itemBuilder: (BuildContext content,int index){
            return Container(
              color: Colors.orange,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Icon(Icons.image,size: 30,),
                  Text("${index+1}",style: TextStyle(color:Colors.white,fontSize: 20),)
                ],
              ),
            );
          }
        )
      ),
    );
  }
}

三、核心属性详解

1. gridDelegate - 网格布局代理

SliverGridDelegateWithFixedCrossAxisCount

less 复制代码
SliverGridDelegateWithFixedCrossAxisCount(
  crossAxisCount: 3,        // 固定列数
  mainAxisSpacing: 10,      // 主轴间距(垂直间距)
  crossAxisSpacing: 10,     // 交叉轴间距(水平间距)
  childAspectRatio: 1.0,    // 子项宽高比(宽度/高度)
)

SliverGridDelegateWithMaxCrossAxisExtent

less 复制代码
SliverGridDelegateWithMaxCrossAxisExtent(
  maxCrossAxisExtent: 200,   // 子项最大宽度
  mainAxisSpacing: 10,    // 行间距
  crossAxisSpacing: 10,   // 列间距
  childAspectRatio: 1.0,  // 长宽比
)

2. 滚动相关属性

less 复制代码
GridView.builder(
  physics: BouncingScrollPhysics(),  // 滚动效果
  shrinkWrap: false,                  // 是否根据内容收缩
  reverse: false,                     // 是否反向滚动
  controller: ScrollController(),     // 滚动控制器
  primary: true,                      // 是否使用主滚动视图
  cacheExtent: 1000,                  // 缓存区域
  addAutomaticKeepAlives: true,       // 是否自动保持存活
  addRepaintBoundaries: true,         // 是否添加重绘边界
  addSemanticIndexes: true,           // 是否添加语义索引
  // ... 其他属性
)

四、实际应用示例

1. 图片网格展示

scala 复制代码
class ImageGrid extends StatelessWidget {
  final List<String> imageUrls;
  
  const ImageGrid({required this.imageUrls});
  
  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
        mainAxisSpacing: 8,
        crossAxisSpacing: 8,
        childAspectRatio: 0.8,
      ),
      itemCount: imageUrls.length,
      itemBuilder: (context, index) {
        return ClipRRect(
          borderRadius: BorderRadius.circular(8),
          child: Image.network(
            imageUrls[index],
            fit: BoxFit.cover,
          ),
        );
      },
    );
  }
}

2. 卡片式网格

less 复制代码
class CardGrid extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GridView.count(
      crossAxisCount: 2,
      mainAxisSpacing: 12,
      crossAxisSpacing: 12,
      padding: EdgeInsets.all(16),
      childAspectRatio: 0.7,
      children: List.generate(10, (index) {
        return Card(
          elevation: 4,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(12),
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Expanded(
                child: Container(
                  decoration: BoxDecoration(
                    color: Colors.grey[300],
                    borderRadius: BorderRadius.vertical(
                      top: Radius.circular(12),
                    ),
                  ),
                ),
              ),
              Padding(
                padding: EdgeInsets.all(8),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Title $index',
                      style: TextStyle(fontWeight: FontWeight.bold),
                    ),
                    SizedBox(height: 4),
                    Text(
                      'Description here',
                      style: TextStyle(fontSize: 12, color: Colors.grey),
                    ),
                  ],
                ),
              ),
            ],
          ),
        );
      }),
    );
  }
}

3. 瀑布流效果

less 复制代码
class WaterfallGrid extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
        maxCrossAxisExtent: 200,
        mainAxisSpacing: 10,
        crossAxisSpacing: 10,
        childAspectRatio: 0.8,
      ),
      itemCount: 20,
      itemBuilder: (context, index) {
        // 随机高度效果
        double height = 100 + (index % 5) * 30;
        return Container(
          height: height,
          decoration: BoxDecoration(
            color: Colors.primaries[index % Colors.primaries.length],
            borderRadius: BorderRadius.circular(8),
          ),
          child: Center(child: Text('Item $index')),
        );
      },
    );
  }
}

五、性能优化技巧

1. 使用builder模式

less 复制代码
// ✅ 推荐:动态构建,只构建可见区域
GridView.builder(
  itemCount: largeList.length,
  itemBuilder: (context, index) => ItemWidget(item: largeList[index]),
)

// ❌ 不推荐:一次性构建所有子项
GridView.count(
  children: largeList.map((item) => ItemWidget(item: item)).toList(),
)

2. 设置合适的缓存区域

less 复制代码
GridView.builder(
  cacheExtent: 500,  // 缓存区域大小,默认为视口大小
  // ...
)

3. 避免在build中创建对象

scala 复制代码
class OptimizedGridView extends StatelessWidget {
  // 提取delegate到外部避免重复创建
  final SliverGridDelegate _delegate = SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2,
    mainAxisSpacing: 10,
    crossAxisSpacing: 10,
  );
  
  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: _delegate,
      itemBuilder: _itemBuilder,
      itemCount: 100,
    );
  }
  
  Widget _itemBuilder(BuildContext context, int index) {
    return Container(
      // 使用const减少重建
      color: Colors.blue,
      child: Text('Item $index'),
    );
  }
}

六、常见问题及解决方案

1. GridView嵌套滚动问题

less 复制代码
// 解决嵌套滚动冲突
SingleChildScrollView(
  child: Column(
    children: [
      Text('Header'),
      Container(
        height: 300,
        child: GridView.builder(
          physics: NeverScrollableScrollPhysics(),  // 禁用内部滚动
          shrinkWrap: true,  // 包裹内容
          // ...
        ),
      ),
    ],
  ),
)

2. 动态改变列数

scala 复制代码
class ResponsiveGridView extends StatelessWidget {
  final int crossAxisCount;
  
  const ResponsiveGridView({required this.crossAxisCount});
  
  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: crossAxisCount,
        mainAxisSpacing: 8,
        crossAxisSpacing: 8,
      ),
      // ...
    );
  }
}

// 使用时
LayoutBuilder(
  builder: (context, constraints) {
    int columns = constraints.maxWidth > 600 ? 3 : 2;
    return ResponsiveGridView(crossAxisCount: columns);
  },
)

3. 空状态处理

scala 复制代码
class GridViewWithEmptyState extends StatelessWidget {
  final List<String> items;
  
  @override
  Widget build(BuildContext context) {
    if (items.isEmpty) {
      return Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(Icons.inbox, size: 64, color: Colors.grey),
            Text('No items found', style: TextStyle(fontSize: 16)),
          ],
        ),
      );
    }
    
    return GridView.builder(
      itemCount: items.length,
      // ...
    );
  }
}

七、总结

选择建议:

  • GridView.count:简单场景,固定列数
  • GridView.extent:响应式布局,自适应列宽
  • GridView.builder:大量数据,需要性能优化
  • GridView.custom:需要完全控制构建过程

注意事项:

  • 大量数据时务必使用builder模式
  • 注意处理空状态和加载状态
  • 合理设置childAspectRatio保持布局美观
  • 考虑不同屏幕尺寸的适配
相关推荐
Gorit11 小时前
使用 AI + Flutter-OH 开发 HarmonyOS 应用
人工智能·flutter·harmonyos
啥都想学点11 小时前
从 Flutter 前端到 Spring Boot 后端:2026 年技术栈落地路线图(实战版)
前端·spring boot·flutter
西西学代码1 天前
Flutter---回调函数
开发语言·javascript·flutter
圣光SG1 天前
Vue.js 从入门到精通:技术成长之路
flutter
恋猫de小郭1 天前
Swift 6.3 正式发布支持 Android ,它能在跨平台发挥什么优势?
android·前端·flutter
i-阿松!1 天前
PCB板子+ flutter前端 + go后端
物联网·flutter·pcb工艺·go1.19
恋猫de小郭1 天前
Flutter 3.41.6 版本很重要,你大概率需要更新一下
android·前端·flutter
亚历克斯神2 天前
Flutter for OpenHarmony: Flutter 三方库 mutex 为鸿蒙异步任务提供可靠的临界资源互斥锁(并发安全基石)
android·数据库·安全·flutter·华为·harmonyos