传递数据到新页面
1. 定义一个描述待办事项的数据类 2. 创建待办事项列表 3. 创建一个待办页面显示待办事件列表 4. 创建一个显示待办事项详细信息的界面 5. 传递数据并跳转到待办事项详细信息界面 或者使用 RouteSettings 传递参数
在开发的过程中,我们经常需要在跳转到新页面的时候,能同时传递一些数据。比如,传递用户点击的元素信息。
还记得么,全屏的界面也只是 widget。在这个例子中,我们会创建一个待办事项列表,当某个事项被点击的时候,会跳转到新的一屏 (widget),在新的一屏显示待办事项的详细信息。
-
定义一个描述待办事项的数据类
-
显示待办事项
-
创建一个显示待办事项详细信息的界面
-
传递数据并跳转到待办事项详细信息界面
1. 定义一个描述待办事项的数据类
#首先,我们需要一个简单的方式来描述待办事项。我们创建一个类叫做 Todo
,包含 title
和 description
两个成员变量。
class Todo {
final String title;
final String description;
const Todo(this.title, this.description);
}
2. 创建待办事项列表
#第二步,我们需要显示一个待办事项列表,生成 20 条待办事项并用 ListView
显示。如果你想了解更多关于列表显示的内容,请阅读文档 基础列表
。
生成待办事项列表
#final todos = List.generate(
20,
(i) => Todo(
'Todo $i',
'A description of what needs to be done for Todo $i',
),
);
用 ListView
显示待办事项列表
#
ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(todos[index].title),
);
},
)
到目前为止,我们生成了 20 条待办事项,并用 ListView
把它显示出来了。
3. 创建一个待办页面显示待办事件列表
#为了实现这个,我们要创建一个无状态的 widget (StatelessWidget
),我们叫它 TodosScreen
。因为这个页面在运行时内容并不会变动,在这个 widget 的 scope 里,我们会把这个待办事项的数组设置为必须 (加入 @require 限定符)。
我们把 ListView.builder
作为 body 的参数返回给 build()
方法,这将会把列表渲染到屏幕上供你继续下一步。
class TodosScreen extends StatelessWidget {
// Requiring the list of todos.
const TodosScreen({super.key, required this.todos});
final List<Todo> todos;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Todos'),
),
//passing in the ListView.builder
body: ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(todos[index].title),
);
},
),
);
}
}
使用 Flutter 自带的样式,未来会变得很轻松。
4. 创建一个显示待办事项详细信息的界面
#现在,我们来创建第二个全屏的界面,界面的标题是待办事项的标题,界面下面显示待办事项的描述信息。
这个界面是一个 StatelessWidget
,创建的时需要传递 Todo
对象给它,它就可以使用传给他的 Todo
对象来构建 UI 。
class DetailScreen extends StatelessWidget {
// In the constructor, require a Todo.
const DetailScreen({super.key, required this.todo});
// Declare a field that holds the Todo.
final Todo todo;
@override
Widget build(BuildContext context) {
// Use the Todo to create the UI.
return Scaffold(
appBar: AppBar(
title: Text(todo.title),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Text(todo.description),
),
);
}
}
5. 传递数据并跳转到待办事项详细信息界面
#上面写完了 DetailScreen
,现在该执行界面跳转啦!我们想让用户在点击列表中的某个待办事项时跳转到 DetailScreen
界面,同时能传递点击的这条代办事项对象(Todo
对象)。
想要获取到用户在 TodosScreen
的点击事件,我们来编写 ListTile
widget 的 onTap()
回调函数,继续使用 Navigator.push()
方法。
body: ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(todos[index].title),
// When a user taps the ListTile, navigate to the DetailScreen.
// Notice that you're not only creating a DetailScreen, you're
// also passing the current todo through to it.
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen(todo: todos[index]),
),
);
},
);
},
),
交互式样例
#import 'package:flutter/material.dart';
class Todo {
final String title;
final String description;
const Todo(this.title, this.description);
}
void main() {
runApp(
MaterialApp(
title: 'Passing Data',
home: TodosScreen(
todos: List.generate(
20,
(i) => Todo(
'Todo $i',
'A description of what needs to be done for Todo $i',
),
),
),
),
);
}
class TodosScreen extends StatelessWidget {
const TodosScreen({super.key, required this.todos});
final List<Todo> todos;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Todos'),
),
body: ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(todos[index].title),
// When a user taps the ListTile, navigate to the DetailScreen.
// Notice that you're not only creating a DetailScreen, you're
// also passing the current todo through to it.
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen(todo: todos[index]),
),
);
},
);
},
),
);
}
}
class DetailScreen extends StatelessWidget {
// In the constructor, require a Todo.
const DetailScreen({super.key, required this.todo});
// Declare a field that holds the Todo.
final Todo todo;
@override
Widget build(BuildContext context) {
// Use the Todo to create the UI.
return Scaffold(
appBar: AppBar(
title: Text(todo.title),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Text(todo.description),
),
);
}
}
或者使用 RouteSettings 传递参数
#重复前面两个步骤。
创建一个详情页以提取参数
#接下来,创建一个详情页用于提取并显示来自 Todo
页面的标题和描述信息。为了访问 Todo
页面,请使用 ModalRoute.of()
方法。它将会返回带有参数的当前路由。
class DetailScreen extends StatelessWidget {
const DetailScreen({super.key});
@override
Widget build(BuildContext context) {
final todo = ModalRoute.of(context)!.settings.arguments as Todo;
// Use the Todo to create the UI.
return Scaffold(
appBar: AppBar(
title: Text(todo.title),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Text(todo.description),
),
);
}
}
导航并向详情页传递参数
#最后,当用户点击 ListTile
widget 时,使用 Navigator.push()
导航到 DetailScreen
。将参数作为 RouteSettings
的一部分进行传递,
DetailScreen
将会提取这些参数。
ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(todos[index].title),
// When a user taps the ListTile, navigate to the DetailScreen.
// Notice that you're not only creating a DetailScreen, you're
// also passing the current todo through to it.
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DetailScreen(),
// Pass the arguments as part of the RouteSettings. The
// DetailScreen reads the arguments from these settings.
settings: RouteSettings(
arguments: todos[index],
),
),
);
},
);
},
)
完整样例
#import 'package:flutter/material.dart';
class Todo {
final String title;
final String description;
const Todo(this.title, this.description);
}
void main() {
runApp(
MaterialApp(
title: 'Passing Data',
home: TodosScreen(
todos: List.generate(
20,
(i) => Todo(
'Todo $i',
'A description of what needs to be done for Todo $i',
),
),
),
),
);
}
class TodosScreen extends StatelessWidget {
const TodosScreen({super.key, required this.todos});
final List<Todo> todos;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Todos'),
),
body: ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(todos[index].title),
// When a user taps the ListTile, navigate to the DetailScreen.
// Notice that you're not only creating a DetailScreen, you're
// also passing the current todo through to it.
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DetailScreen(),
// Pass the arguments as part of the RouteSettings. The
// DetailScreen reads the arguments from these settings.
settings: RouteSettings(
arguments: todos[index],
),
),
);
},
);
},
),
);
}
}
class DetailScreen extends StatelessWidget {
const DetailScreen({super.key});
@override
Widget build(BuildContext context) {
final todo = ModalRoute.of(context)!.settings.arguments as Todo;
// Use the Todo to create the UI.
return Scaffold(
appBar: AppBar(
title: Text(todo.title),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Text(todo.description),
),
);
}
}
除非另有说明,本文档之所提及适用于 Flutter 的最新稳定版本,本页面最后更新时间: 2024-07-03。 查看文档源码 或者 为本页面内容提出建议。