我们经常需要创建展示不同类型内容的列表。比方说,我们可能在开发一个列表,它显示一个标题,后跟一些与标题相关的项目,然后是另一个标题,依此类推。
我们该如何用 Flutter 创建这样的结构呢?
路线
创建一个拥有不同类型项目的数据源
把数据源转换成一个包含 Widget 的 List
1. 创建一个具有不同类型项目的数据源
项目的类型
为了表示 List 中不同类型的项,我们需要为每一个类型的项目定义一个类。
在这个例子中,我们将制作一个展示了标题,后面有五条消息的应用。因此,我们将创建三个类:ListItem
、HeadingItem
和 MessageItem
。
// 一个 List 可以包含的不同类型项的基类(The base class for the different types of items the List can contain)
abstract class ListItem {}
// 包含标题数据的一种 ListItem(A ListItem that contains data to display a heading)
class HeadingItem implements ListItem {
final String heading;
HeadingItem(this.heading);
}
// 包含消息数据的一种 ListItem(A ListItem that contains data to display a message)
class MessageItem implements ListItem {
final String sender;
final String body;
MessageItem(this.sender, this.body);
}
创建项目的 List
大部分时候,我们从网络或本地数据库获取数据,并将数据转换成一个项目列表。
对于这个例子来说,我们将生成一个要使用的项目列表。这个列表将包含一个标题,后跟五条消息。如此往复。
final items = List<ListItem>.generate(
1200,
(i) => i % 6 == 0
? HeadingItem("Heading $i")
: MessageItem("Sender $i", "Message body $i"),
);
2. 把数据源转换成 Widget 的 List
为了把每一个项目转换成 Widget,我们将采用 ListView.builder
构造方法。
通常,我们需要提供一个 builder
函数来确定我们正在处理的项目类型,并返回该类型项目的相应 Widget。
在这个例子中,我们使用 is
关键字来检查我们正在处理的项目类型。这样做速度很快,并会自动将每个项目转换为适当的类型。不过,如果你更喜欢其他模式,也能通过其他方式解决此问题!
ListView.builder(
// 让 ListView 知道有多少项目需要被构建(Let the ListView know how many items it needs to build)
itemCount: items.length,
// 提供一个 builder 方法。这正是魔力所在!(Provide a builder function. This is where the magic happens! We'll)
// 我们将基于各个项目本身的类型,转化成 Widget。(convert each item into a Widget based on the type of item it is.)
itemBuilder: (context, index) {
final item = items[index];
if (item is HeadingItem) {
return ListTile(
title: Text(
item.heading,
style: Theme.of(context).textTheme.headline,
),
);
} else if (item is MessageItem) {
return ListTile(
title: Text(item.sender),
subtitle: Text(item.body),
);
}
},
);
完整示例
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp(
items: List<ListItem>.generate(
1000,
(i) => i % 6 == 0
? HeadingItem("Heading $i")
: MessageItem("Sender $i", "Message body $i"),
),
));
}
class MyApp extends StatelessWidget {
final List<ListItem> items;
MyApp({Key key, @required this.items}) : super(key: key);
@override
Widget build(BuildContext context) {
final title = 'Mixed List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: ListView.builder(
// 让 ListView 知道有多少项目需要被构建(Let the ListView know how many items it needs to build)
itemCount: items.length,
// 提供一个 builder 方法。这正是魔力所在!(Provide a builder function. This is where the magic happens! We'll)
// 我们将基于各个项目本身的类型,转化成 Widget。(convert each item into a Widget based on the type of item it is.)
itemBuilder: (context, index) {
final item = items[index];
if (item is HeadingItem) {
return ListTile(
title: Text(
item.heading,
style: Theme.of(context).textTheme.headline,
),
);
} else if (item is MessageItem) {
return ListTile(
title: Text(item.sender),
subtitle: Text(item.body),
);
}
},
),
),
);
}
}
// List 能容纳的不同类型项目的基类(The base class for the different types of items the List can contain)
abstract class ListItem {}
// 一种包含展示标题数据的 ListItem(A ListItem that contains data to display a heading)
class HeadingItem implements ListItem {
final String heading;
HeadingItem(this.heading);
}
// 一种包含展示消息数据的 ListItem(A ListItem that contains data to display a message)
class MessageItem implements ListItem {
final String sender;
final String body;
MessageItem(this.sender, this.body);
}
当前内容版权归 flutter-io.cn 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 flutter-io.cn .