将数据发送到新屏幕
- 1. 定义一个 todo 类
- 2. 创建一个 todo 列表
- 3. 创建一个 Todo 屏幕来显示列表
- 4. 创建一个详细信息屏幕来显示有关 todo 的信息
- 5. 导航并传递数据到详细信息屏幕
- 或者,使用 RouteSettings 传递参数
通常,您不仅希望导航到新屏幕,还希望将数据传递到该屏幕。例如,您可能希望传递有关已点击项目的的信息。
记住:屏幕只是小部件。在本例中,创建一个待办事项列表。当点击待办事项时,导航到一个新的屏幕(小部件),该屏幕显示有关待办事项的信息。此食谱使用以下步骤
- 定义一个待办事项类。
- 显示待办事项列表。
- 创建一个可以显示有关待办事项信息的详细信息屏幕。
- 导航并将数据传递到详细信息屏幕。
1. 定义一个 todo 类
#首先,您需要一种简单的方法来表示待办事项。在本例中,创建一个包含两部分数据的类:标题和描述。
class Todo {
final String title;
final String description;
const Todo(this.title, this.description);
}
2. 创建一个 todo 列表
#其次,显示待办事项列表。在本例中,生成 20 个待办事项,并使用 ListView 显示它们。有关使用列表的更多信息,请参阅使用列表食谱。
生成 todo 列表
#final todos = List.generate(
20,
(i) => Todo(
'Todo $i',
'A description of what needs to be done for Todo $i',
),
);
使用 ListView 显示 todo 列表
#ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(todos[index].title),
);
},
),
到目前为止,一切都很好。这将生成 20 个待办事项并在 ListView 中显示它们。
3. 创建一个 Todo 屏幕来显示列表
#为此,我们创建一个StatelessWidget
。我们将其称为TodosScreen
。由于此页面的内容在运行时不会改变,因此我们必须在该小部件的范围内要求待办事项列表。
我们将ListView.builder
作为要返回给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. 创建一个详细信息屏幕来显示有关 todo 的信息
#现在,创建第二个屏幕。屏幕的标题包含待办事项的标题,屏幕的主体显示描述。
由于详细信息屏幕是一个普通的StatelessWidget
,因此要求用户在 UI 中输入一个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
。将待办事项传递给 DetailScreen
。
为了捕获用户在 TodosScreen
中的点击,请为 ListTile
小部件编写一个 onTap()
回调。在 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
小部件时,使用 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),
),
);
}
}