Flutter ListView 组件及各种模式


一、ListView 是什么?

在 Flutter 中,ListView 是一个用于展示 可滚动列表 的基础组件,它是最常用的滚动组件之一。

你可以把它理解为:

类似于 Android 的 RecyclerView或 iOS 的 UITableView,用于在竖直或水平方向上展示一系列可滚动的条目(items)。


二、ListView 的基本用法

1. 最简单的垂直列表(默认方向)

ListView(
  children: [
    ListTile(title: Text('Item 1')),
    ListTile(title: Text('Item 2')),
    ListTile(title: Text('Item 3')),
  ],
)
  • children: 是一个 Widget 列表,代表你要展示的所有子项。
  • 默认是 垂直滚动(从上到下)

三、ListView 的几种构造函数(模式)

Flutter 提供了 多个 ListView 的构造函数,每种适用于不同的使用场景。主要包括:

构造函数 适用场景 特点
ListView 子项数量较少、已知全部子项 直接传入 children列表
ListView.builder 子项数量较多或动态生成(推荐) 按需构建,性能更好,适合长列表
ListView.separated 需要在每个 item 之间添加分隔线或间隔 在 builder 基础上增加分隔 widget
ListView.custom 需要完全自定义滚动行为和 item 布局 使用 SliverChildDelegate,高级用法

我们重点讲解前面 3 种,也是实际开发中最常用的。


四、1. ListView(直接传 children,适合少量固定列表)

用法:

ListView(
  children: [
    ListTile(title: Text('首页')),
    ListTile(title: Text('发现')),
    ListTile(title: Text('我的')),
    Container(height: 100, color: Colors.amber, child: Center(child: Text('其他内容'))),
  ],
)

特点:

  • 适合 列表项数量少、固定不变 的情况。
  • 所有的子 Widget 会 一次性构建,如果列表很长(比如 1000 个),会导致性能问题,甚至卡顿。

五、2. ListView.builder(推荐:动态/长列表,按需构建)

用法:

ListView.builder(
  itemCount: 20, // 列表项总数
  itemBuilder: (BuildContext context, int index) {
    return ListTile(
      leading: Icon(Icons.star),
      title: Text('Item $index'),
    );
  },
)

参数说明:

参数 说明
itemCount 列表中有多少项
itemBuilder 回调函数,返回每一项的 Widget,参数是 context和当前索引 index

特点:

  • 按需构建(懒加载),只构建当前屏幕可见的 item,极大提升性能,是开发长列表的首选。
  • 适合:从网络/数据库加载的数据列表、聊天记录、商品列表等动态内容

六、3. ListView.separated(带分隔线的列表)

用法:

ListView.separated(
  itemCount: 10,
  separatorBuilder: (BuildContext context, int index) {
    return Divider(color: Colors.grey); // 分隔线
  },
  itemBuilder: (BuildContext context, int index) {
    return ListTile(
      title: Text('Item $index'),
    );
  },
)

参数说明:

  • separatorBuilder: 用于构建 每一项之间的分隔 Widget,比如 DividerSizedBox
  • 其它参数同 ListView.builder

效果:

  • 每个 item 之间会显示一个分割线(或其他你定义的间隔组件)。
  • 常用于:列表需要明显区分每一项的场景,如设置页、通讯录等

七、ListView 的滚动方向

默认是 垂直滚动(Axis.vertical),但也可以设置为 水平滚动(Axis.horizontal),通常配合 ListView.builder使用。

水平滚动的例子(横向列表):

ListView.builder(
  scrollDirection: Axis.horizontal, // 水平滚动
  itemCount: 10,
  itemBuilder: (context, index) {
    return Container(
      width: 100,
      margin: EdgeInsets.all(8),
      color: Colors.primaries[index % Colors.primaries.length],
      alignment: Alignment.center,
      child: Text('Item $index'),
    );
  },
)

说明:

  • scrollDirection: Axis.horizontal让列表横向滚动
  • 每个 item 需要指定宽度(比如 width: 100),否则会挤在一起

八、ListView 常用搭配组件

组件 说明 适用场景
ListTile 带图标、标题、副标题的列表项 设置页、菜单列表等
Container 自定义布局容器 列表项内容布局
Card 带阴影的卡片容器 商品列表、内容卡片
Divider / SizedBox 分隔线或间距 分隔列表项
GridView 网格布局(二维列表) 图片墙、瀑布流等
SliverList 高级自定义滚动列表(在 CustomScrollView 中使用) 复杂滚动布局

九、ListView 与其它滚动组件的关系

组件 说明
ListView 基本的垂直/水平列表
SingleChildScrollView + Column 简单滚动容器,但子项全部构建,不适合长列表
CustomScrollView + SliverList 更加灵活的自定义滚动视图,ListView 是其一种实现
GridView 网格形式的滚动列表
PageView 页面横向滑动(比如引导页)

十、ListView 性能优化建议

优化点 建议
列表项很多? 一定要用 ListView.builderseparated,不要用 ListView(children: [])
图片加载慢? 使用 cached_network_image等图片缓存库
cell 复杂? 减少嵌套,优化 widget tree,考虑使用 const构造函数
数据来自网络? 结合 FutureBuilder或状态管理(如 Provider、Riverpod、Bloc)异步加载
滚动卡顿? 检查是否一次性构建太多 widget,尽量使用懒加载模式

十一、总结:ListView 的几种模式对比

模式 构造函数 适用场景 特点
基础列表 ListView(children: []) 列表项少、固定 一次性构建所有子项,简单但性能差
动态列表(推荐) ListView.builder 列表项多、动态生成 按需构建,性能好,适合长列表
带分隔线列表 ListView.separated 需要 item 间分隔 在 builder 基础上增加分隔 widget
自定义滚动 ListView.custom 需要完全控制列表布局 使用 SliverChildDelegate,高级用法
水平列表 ListView(scrollDirection: Axis.horizontal) 横向滑动内容 比如轮播图、横向菜单

十二、完整示例:一个实用的 ListView.builder 列表

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('ListView 示例')),
        body: MyListView(),
      ),
    );
  }
}

class MyListView extends StatelessWidget {
  final List<String> items = List.generate(50, (index) => '列表项 ${index + 1}');

  
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: items.length,
      itemBuilder: (context, index) {
        return ListTile(
          leading: Icon(Icons.article),
          title: Text(items[index]),
          onTap: () {
            print('你点击了:${items[index]}');
          },
        );
      },
    );
  }
}
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新

更多推荐