在某些情况下,我们可能想要从新页面返回数据。例如,假设我们导航到了一个新页面,向用户呈现两个选项。当用户点击某个选项时,我们需要将用户选择通知给第一个页面,以便它能够处理这些信息!

我们如何实现?使用Navigator.pop

步骤

  1. 定义主页。
  2. 添加一个打开选择页面的按钮。
  3. 在选择页面上显示两个按钮。
  4. 点击一个按钮时,关闭选择的页面。
  5. 主页上弹出一个snackbar以显示用户的选择。

1. 定义主页

主页将显示一个按钮。点击后,它将打开选择页面!

  1. class HomeScreen extends StatelessWidget {
  2. @override
  3. Widget build(BuildContext context) {
  4. return new Scaffold(
  5. appBar: new AppBar(
  6. title: new Text('Returning Data Demo'),
  7. ),
  8. // We'll create the SelectionButton Widget in the next step
  9. body: new Center(child: new SelectionButton()),
  10. );
  11. }
  12. }

2. 添加一个打开选择页面的按钮。

现在,我们将创建我们的SelectionButton。我们的选择按钮将会:

  1. 点击时启动SelectionScreen
  2. 等待SelectionScreen返回结果
  1. class SelectionButton extends StatelessWidget {
  2. @override
  3. Widget build(BuildContext context) {
  4. return new RaisedButton(
  5. onPressed: () {
  6. _navigateAndDisplaySelection(context);
  7. },
  8. child: new Text('Pick an option, any option!'),
  9. );
  10. }
  11. // A method that launches the SelectionScreen and awaits the result from
  12. // Navigator.pop
  13. _navigateAndDisplaySelection(BuildContext context) async {
  14. // Navigator.push returns a Future that will complete after we call
  15. // Navigator.pop on the Selection Screen!
  16. final result = await Navigator.push(
  17. context,
  18. // We'll create the SelectionScreen in the next step!
  19. new MaterialPageRoute(builder: (context) => new SelectionScreen()),
  20. );
  21. }
  22. }

3. 在选择页面上显示两个按钮。

现在,我们需要构建一个选择页面!它将包含两个按钮。当用户点击按钮时,应该关闭选择页面并让主页知道哪个按钮被点击!

现在,我们将定义UI,并确定如何在下一步中返回数据。

  1. class SelectionScreen extends StatelessWidget {
  2. @override
  3. Widget build(BuildContext context) {
  4. return new Scaffold(
  5. appBar: new AppBar(
  6. title: new Text('Pick an option'),
  7. ),
  8. body: new Center(
  9. child: new Column(
  10. mainAxisAlignment: MainAxisAlignment.center,
  11. children: <Widget>[
  12. new Padding(
  13. padding: const EdgeInsets.all(8.0),
  14. child: new RaisedButton(
  15. onPressed: () {
  16. // Pop here with "Yep"...
  17. },
  18. child: new Text('Yep!'),
  19. ),
  20. ),
  21. new Padding(
  22. padding: const EdgeInsets.all(8.0),
  23. child: new RaisedButton(
  24. onPressed: () {
  25. // Pop here with "Nope"
  26. },
  27. child: new Text('Nope.'),
  28. ),
  29. )
  30. ],
  31. ),
  32. ),
  33. );
  34. }
  35. }

4. 点击一个按钮时,关闭选择的页面。

现在,我们完成两个按钮的onPressed回调。为了将数据返回到第一个页面,我们需要使用Navitator.pop方法。

Navigator.pop接受一个可选的(第二个)参数result。如果我们返回结果,它将返回到一个Future到主页的SelectionButton中!

Yep 按钮

  1. new RaisedButton(
  2. onPressed: () {
  3. // Our Yep button will return "Yep!" as the result
  4. Navigator.pop(context, 'Yep!');
  5. },
  6. child: new Text('Yep!'),
  7. );

Nope 按钮

  1. new RaisedButton(
  2. onPressed: () {
  3. // Our Nope button will return "Nope!" as the result
  4. Navigator.pop(context, 'Nope!');
  5. },
  6. child: new Text('Nope!'),
  7. );

5. 主页上弹出一个snackbar以显示用户的选择。

既然我们正在启动一个选择页面并等待结果,那么我们会想要对返回的信息进行一些操作!

在这种情况下,我们将显示一个显示结果的Snackbar。为此,我们将更新SelectionButton中的_navigateAndDisplaySelection方法。

  1. _navigateAndDisplaySelection(BuildContext context) async {
  2. final result = await Navigator.push(
  3. context,
  4. new MaterialPageRoute(builder: (context) => new SelectionScreen()),
  5. );
  6. // After the Selection Screen returns a result, show it in a Snackbar!
  7. Scaffold
  8. .of(context)
  9. .showSnackBar(new SnackBar(content: new Text("$result")));
  10. }

完整的例子

  1. import 'package:flutter/material.dart';
  2. void main() {
  3. runApp(new MaterialApp(
  4. title: 'Returning Data',
  5. home: new HomeScreen(),
  6. ));
  7. }
  8. class HomeScreen extends StatelessWidget {
  9. @override
  10. Widget build(BuildContext context) {
  11. return new Scaffold(
  12. appBar: new AppBar(
  13. title: new Text('Returning Data Demo'),
  14. ),
  15. body: new Center(child: new SelectionButton()),
  16. );
  17. }
  18. }
  19. class SelectionButton extends StatelessWidget {
  20. @override
  21. Widget build(BuildContext context) {
  22. return new RaisedButton(
  23. onPressed: () {
  24. _navigateAndDisplaySelection(context);
  25. },
  26. child: new Text('Pick an option, any option!'),
  27. );
  28. }
  29. // A method that launches the SelectionScreen and awaits the result from
  30. // Navigator.pop!
  31. _navigateAndDisplaySelection(BuildContext context) async {
  32. // Navigator.push returns a Future that will complete after we call
  33. // Navigator.pop on the Selection Screen!
  34. final result = await Navigator.push(
  35. context,
  36. new MaterialPageRoute(builder: (context) => new SelectionScreen()),
  37. );
  38. // After the Selection Screen returns a result, show it in a Snackbar!
  39. Scaffold
  40. .of(context)
  41. .showSnackBar(new SnackBar(content: new Text("$result")));
  42. }
  43. }
  44. class SelectionScreen extends StatelessWidget {
  45. @override
  46. Widget build(BuildContext context) {
  47. return new Scaffold(
  48. appBar: new AppBar(
  49. title: new Text('Pick an option'),
  50. ),
  51. body: new Center(
  52. child: new Column(
  53. mainAxisAlignment: MainAxisAlignment.center,
  54. children: <Widget>[
  55. new Padding(
  56. padding: const EdgeInsets.all(8.0),
  57. child: new RaisedButton(
  58. onPressed: () {
  59. // Close the screen and return "Yep!" as the result
  60. Navigator.pop(context, 'Yep!');
  61. },
  62. child: new Text('Yep!'),
  63. ),
  64. ),
  65. new Padding(
  66. padding: const EdgeInsets.all(8.0),
  67. child: new RaisedButton(
  68. onPressed: () {
  69. // Close the screen and return "Nope!" as the result
  70. Navigator.pop(context, 'Nope.');
  71. },
  72. child: new Text('Nope.'),
  73. ),
  74. )
  75. ],
  76. ),
  77. ),
  78. );
  79. }
  80. }