当你的内容超出一个屏幕的高度时,你就需要一个可滚动的容器。ListView 和 GridView 是 Flutter 中最重要、最常用的可滚动组件,它们专门用于高效地展示大量数据。理解它们的不同构造方式和适用场景对于构建高性能的应用至关-重要。
学习目标
- 理解 
ListView最常用的三种构造函数:默认构造函数、.builder()和.separated(),并了解它们各自的性能特点和适用场景。 - 掌握 
GridView的核心概念SliverGridDelegate,并学会使用GridView.count()和GridView.builder()来创建网格布局。 - 学会根据具体需求选择最合适的列表或网格实现方式。
 
1. ListView:线性可滚动列表
ListView 是一个将子组件沿垂直(默认)或水平方向线性排列的可滚动组件。
方式一:默认构造函数 ListView()
这是最简单的方式,它接收一个 List<Widget> 作为 children。
- 特点 :一次性创建并渲染列表中的所有子组件。
 - 适用场景 :当列表项数量很少且固定时。例如,一个设置页面,里面只有十几个固定的选项。
 - 性能陷阱 :绝对不要用这种方式来展示一个很长或无限的列表!因为它会一次性把所有 Widget 都加载到内存中,即使它们在屏幕外,这会导致严重的性能问题和内存占用。
 
            
            
              dart
              
              
            
          
          ListView(
  padding: const EdgeInsets.all(8),
  children: <Widget>[
    Container(height: 50, color: Colors.amber[600], child: const Center(child: Text('Entry A'))),
    Container(height: 50, color: Colors.amber[500], child: const Center(child: Text('Entry B'))),
    Container(height: 50, color: Colors.amber[100], child: const Center(child: Text('Entry C'))),
  ],
)
        方式二:ListView.builder()【最常用、性能最好】
这是构建长列表的标准和推荐 方式。它采用"懒加载"机制,只创建和渲染那些当前在屏幕上可见的列表项。
- 特点:按需构建,性能极高。
 - 核心属性 :
itemCount: 列表项的总数。itemBuilder: 一个函数,用于构建每个列表项的 Widget。它接收context和index(当前项的索引)作为参数。
 - 适用场景:几乎所有长列表或数据量不确定的列表,如新闻 Feed、聊天记录、商品列表等。
 
代码示例:构建一个动态新闻列表
            
            
              less
              
              
            
          
          import 'package:flutter/material.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    // 假设这是从 API 获取的数据
    final List<String> entries = List<String>.generate(50, (i) => 'News Article ${i + 1}');
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('ListView.builder Demo')),
        body: ListView.builder(
          itemCount: entries.length, // 1. 告诉 ListView 总共有多少项
          itemBuilder: (BuildContext context, int index) { // 2. 按需构建每一项
            return ListTile(
              leading: CircleAvatar(child: Text('${index + 1}')),
              title: Text(entries[index]),
              subtitle: Text('This is the subtitle for item $index'),
              onTap: () {
                print('Tapped on ${entries[index]}');
              },
            );
          },
        ),
      ),
    );
  }
}
        方式三:ListView.separated()
这个构造函数与 .builder() 非常相似,但增加了一个额外的 separatorBuilder 函数,用于在每个列表项之间构建一个分隔符 Widget。
- 特点 :在 
.builder()的基础上,可以方便地添加自定义的分隔线。 - 适用场景:需要明确分隔符的列表,如联系人列表、设置菜单等。
 
            
            
              dart
              
              
            
          
          ListView.separated(
  itemCount: 25,
  separatorBuilder: (BuildContext context, int index) => const Divider(color: Colors.grey), // 分隔符构建器
  itemBuilder: (BuildContext context, int index) {
    return ListTile(
      title: Text('Item $index'),
    );
  },
)
        2. GridView:二维可滚动网格
GridView 用于在二维空间中排列子组件,常用于相册、商品分类等场景。
核心概念:gridDelegate
GridView 的布局方式由 gridDelegate 属性控制,它接收一个 SliverGridDelegate 对象。这个 "delegate" (委托) 告诉 GridView 如何排列其子项。最常用的有两个:
- 
SliverGridDelegateWithFixedCrossAxisCount:- 创建一个在交叉轴 上具有固定数量的网格。
 - 例如,在垂直滚动的 
GridView中,交叉轴是水平的,crossAxisCount: 3就意味着每行固定有 3 个子项。 
 - 
SliverGridDelegateWithMaxCrossAxisExtent:- 创建一个子项在交叉轴 上具有最大宽度/高度的网格。
 - 例如,
maxCrossAxisExtent: 150意味着每个子项的宽度最多为 150 像素。GridView会根据屏幕总宽度自动计算一行能放几个子项。这对于构建响应式布局非常有用。 
 
方式一:GridView.count()
这是 SliverGridDelegateWithFixedCrossAxisCount 的一个便捷构造函数。
- 特点:简单直观,快速创建一个固定列数的网格。
 - 适用场景:当你明确知道每行需要显示几个项目时。
 
            
            
              dart
              
              
            
          
          GridView.count(
  crossAxisCount: 3, // 每行3个
  mainAxisSpacing: 10,  // 主轴间距
  crossAxisSpacing: 10, // 交叉轴间距
  children: List.generate(20, (index) {
    return Container(
      color: Colors.teal[100 * (index % 9)],
      child: Center(child: Text('Item $index')),
    );
  }),
)
        方式二:GridView.builder()【性能最好】
与 ListView.builder() 类似,GridView.builder() 也采用懒加载机制,是构建大型网格的首选。
- 特点 :按需构建,高性能,与 
gridDelegate结合使用,布局灵活。 - 适用场景:需要展示大量数据的相册、商品目录等。
 
代码示例:构建一个商品展示网格
            
            
              less
              
              
            
          
          import 'package:flutter/material.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('GridView.builder Demo')),
        body: GridView.builder(
          padding: const EdgeInsets.all(10.0),
          // 1. 提供 Grid Delegate
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 2,    // 每行2个
            crossAxisSpacing: 10, // 水平间距
            mainAxisSpacing: 10,  // 垂直间距
            childAspectRatio: 3 / 2, // 宽高比
          ),
          itemCount: 30, // 2. 网格项总数
          itemBuilder: (BuildContext context, int index) { // 3. 按需构建
            return Container(
              padding: const EdgeInsets.all(8),
              color: Colors.blueGrey,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  const Icon(Icons.shopping_bag, size: 40, color: Colors.white),
                  Text(
                    'Product $index',
                    style: const TextStyle(color: Colors.white, fontSize: 18),
                  ),
                ],
              ),
            );
          },
        ),
      ),
    );
  }
}
        总结:如何选择?
- 
确定数据量:
- 数据量小且固定? -> 可以使用 
ListView()或GridView.count()的默认构造函数。 - 数据量大或不确定? -> 必须使用 
ListView.builder或GridView.builder以保证性能。 
 - 数据量小且固定? -> 可以使用 
 - 
确定布局样式:
- 单列垂直/水平滚动列表? -> 
ListView。 - 需要分隔符? -> 
ListView.separated。 - 多行多列的网格布局? -> 
GridView。 
 - 单列垂直/水平滚动列表? -> 
 - 
确定网格列数:
- 固定列数? -> 
GridView.count或GridView.builder+SliverGridDelegateWithFixedCrossAxisCount。 - 希望根据屏幕宽度自适应列数? -> 
GridView.builder+SliverGridDelegateWithMaxCrossAxisExtent。 
 - 固定列数? -> 
 
掌握了 ListView 和 GridView 的高效用法,你就具备了构建流畅、可响应的数据密集型应用的核心能力。接下来,我们将进入 Flutter 开发中另一个至关重要的主题:页面导航与路由管理。我们下篇见!