列表组件详解
列表组件是展示数据的常用方式,Flutter 提供了多种列表组件来满足不同的需求。本教程将详细介绍 ListView、GridView 等列表组件。
重要提示:Flutter 3.27+ 优化了列表性能,特别是在大量数据和滚动场景下。
1. ListView 列表视图
ListView 是最常用的列表组件,支持垂直和水平滚动,可以动态生成列表项。
核心属性
| 属性 | 类型 | 说明 |
|---|---|---|
| scrollDirection | Axis | 滚动方向(垂直或水平) |
| reverse | bool | 是否反向滚动 |
| controller | ScrollController | 滚动控制器 |
| primary | bool | 是否为主滚动视图 |
| physics | ScrollPhysics | 滚动物理特性 |
| shrinkWrap | bool | 是否根据子组件尺寸调整大小 |
| padding | EdgeInsets | 内边距 |
使用示例
// 基本 ListView(静态列表)
ListView(
children: const [
ListTile(
leading: Icon(Icons.person),
title: Text('Alice'),
subtitle: Text('Software Engineer'),
),
ListTile(
leading: Icon(Icons.person),
title: Text('Bob'),
subtitle: Text('Designer'),
),
ListTile(
leading: Icon(Icons.person),
title: Text('Charlie'),
subtitle: Text('Manager'),
),
],
)
// ListView.builder(动态列表)
final List _items = List.generate(100, (index) => 'Item $index');
ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(_items[index]),
onTap: () {
print('点击: ${_items[index]}');
},
);
},
)
// ListView.separated(带分隔符)
ListView.separated(
itemCount: _items.length,
separatorBuilder: (context, index) => const Divider(),
itemBuilder: (context, index) {
return ListTile(
title: Text(_items[index]),
);
},
)
// 水平 ListView
ListView(
scrollDirection: Axis.horizontal,
children: [
Container(
width: 200,
color: Colors.red,
child: const Center(child: Text('红色')),
),
Container(
width: 200,
color: Colors.green,
child: const Center(child: Text('绿色')),
),
Container(
width: 200,
color: Colors.blue,
child: const Center(child: Text('蓝色')),
),
],
)
// 带 Card 的 ListView
ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: 10,
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.symmetric(vertical: 4),
child: ListTile(
leading: CircleAvatar(
child: Text('${index + 1}'),
),
title: Text('项目 ${index + 1}'),
subtitle: Text('这是项目 ${index + 1} 的描述'),
trailing: const Icon(Icons.arrow_forward),
onTap: () {
print('点击项目 ${index + 1}');
},
),
);
},
)
技巧:对于大量数据,使用 ListView.builder 而不是 ListView(children: []),以提高性能。
2. GridView 网格视图
GridView 以网格形式展示子组件,支持多种布局模式。
使用示例
// GridView.count(固定列数)
GridView.count(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
children: List.generate(20, (index) {
return Container(
color: Colors.primaries[index % Colors.primaries.length],
child: Center(
child: Text(
'$index',
style: const TextStyle(
color: Colors.white,
fontSize: 24,
),
),
),
);
}),
)
// GridView.extent(固定宽度)
GridView.extent(
maxCrossAxisExtent: 150,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
children: List.generate(20, (index) {
return Card(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.star,
size: 48,
color: Colors.primaries[index % Colors.primaries.length],
),
const SizedBox(height: 8),
Text('项目 $index'),
],
),
);
}),
)
// GridView.builder(动态网格)
GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 1.0,
),
itemCount: 50,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
color: Colors.primaries[index % Colors.primaries.length],
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text(
'$index',
style: const TextStyle(
color: Colors.white,
fontSize: 20,
),
),
),
);
},
)
// 自定义网格布局
GridView.builder(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
childAspectRatio: 3/4,
),
itemCount: 12,
itemBuilder: (context, index) {
return Card(
clipBehavior: Clip.antiAlias,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Container(
color: Colors.primaries[index % Colors.primaries.length],
child: Center(
child: Icon(
Icons.image,
size: 48,
color: Colors.white,
),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'图片 $index',
textAlign: TextAlign.center,
),
),
],
),
);
},
)
3. ListTile 列表项
ListTile 是 Material Design 风格的列表项组件,提供了丰富的布局选项。
使用示例
// 基本 ListTile
ListTile(
leading: const Icon(Icons.person),
title: const Text('Alice'),
subtitle: const Text('Software Engineer'),
trailing: const Icon(Icons.arrow_forward),
onTap: () {
print('点击 Alice');
},
)
// 带复选框的 ListTile
CheckboxListTile(
title: const Text('启用通知'),
subtitle: const Text('接收推送通知'),
value: _notificationsEnabled,
onChanged: (bool? value) {
setState(() {
_notificationsEnabled = value ?? false;
});
},
)
// 带开关的 ListTile
SwitchListTile(
title: const Text('飞行模式'),
subtitle: const Text('禁用无线连接'),
value: _airplaneMode,
onChanged: (bool value) {
setState(() {
_airplaneMode = value;
});
},
)
// 带图片的 ListTile
ListTile(
leading: const CircleAvatar(
backgroundImage: NetworkImage('https://via.placeholder.com/150'),
),
title: const Text('用户名'),
subtitle: const Text('用户简介'),
trailing: const Icon(Icons.more_vert),
onTap: () {
print('查看用户详情');
},
)
// 三行 ListTile
ListTile(
leading: const Icon(Icons.email),
title: const Text('邮件标题'),
subtitle: const Text('邮件副标题'),
trailing: const Icon(Icons.star_border),
isThreeLine: true,
onTap: () {
print('查看邮件');
},
)
4. CustomScrollView 自定义滚动视图
CustomScrollView 可以创建复杂的滚动效果,如固定头部、吸顶效果等。
使用示例
// 带 SliverAppBar 的 CustomScrollView
CustomScrollView(
slivers: [
SliverAppBar(
expandedHeight: 200,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: const Text('标题'),
background: Container(
color: Colors.blue,
child: const Center(
child: Icon(
Icons.image,
size: 100,
color: Colors.white,
),
),
),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return ListTile(
title: Text('项目 $index'),
);
},
childCount: 20,
),
),
],
)
// 多个 Sliver 的组合
CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Container(
height: 200,
color: Colors.red,
child: const Center(child: Text('头部内容')),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return ListTile(
title: Text('项目 $index'),
);
},
childCount: 10,
),
),
SliverGrid(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
color: Colors.blue,
child: Center(child: Text('Grid $index')),
);
},
childCount: 10,
),
),
],
)
技巧:使用 CustomScrollView 可以实现吸顶效果、视差滚动等复杂效果。
5. RefreshIndicator 下拉刷新
RefreshIndicator 为可滚动组件添加下拉刷新功能。
使用示例
// 基本 RefreshIndicator
RefreshIndicator(
onRefresh: _refreshData,
child: ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(_items[index]),
);
},
),
)
// 刷新函数
Future _refreshData() async {
await Future.delayed(const Duration(seconds: 2));
setState(() {
_items = List.generate(20, (index) => '刷新项目 $index');
});
}
6. ScrollController 滚动控制
ScrollController 用于控制滚动行为,如滚动到指定位置、监听滚动事件等。
使用示例
class MyListView extends StatefulWidget {
const MyListView({super.key});
@override
State createState() => _MyListViewState();
}
class _MyListViewState extends State {
final ScrollController _scrollController = ScrollController();
bool _showScrollToTop = false;
@override
void initState() {
super.initState();
_scrollController.addListener(() {
setState(() {
_showScrollToTop = _scrollController.offset > 200;
});
});
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
void _scrollToTop() {
_scrollController.animateTo(
0,
duration: const Duration(milliseconds: 500),
curve: Curves.easeInOut,
);
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
ListView.builder(
controller: _scrollController,
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(
title: Text('项目 $index'),
);
},
),
if (_showScrollToTop)
Positioned(
bottom: 20,
right: 20,
child: FloatingActionButton(
onPressed: _scrollToTop,
child: const Icon(Icons.arrow_upward),
),
),
],
);
}
}
列表组件最佳实践
- 对于大量数据,使用 ListView.builder 或 GridView.builder
- 为列表项添加合适的分割线或间距
- 使用 const 构造函数提高性能
- 为图片列表使用缓存,如 CachedNetworkImage
- 使用 ListView.separated 添加分割线
- 合理使用 Padding 和 margin 调整间距
- 为长列表添加加载更多功能
- 使用 RefreshIndicator 提供下拉刷新
- 使用 ScrollController 监听和控制滚动
进阶学习:掌握列表组件后,可以学习 ScrollPhysics 和 ScrollController 实现更复杂的滚动效果。