在某些场景下,我们需要在回退到上一屏时同时返回一些数据。比如,我们跳转到新的一屏,有两个选项让用户选择,当用户点击某个选项后会返回到第一屏,同时在第一屏可以知道用户选择的信息。

这里我们要怎么做呢? 使用 Navigator.pop

步骤

  • 创建主屏界面

  • 添加按钮,点击时跳转到选择界面

  • 在选择界面显示两个按钮

  • 当任意一个按钮被点击,关闭选择界面回退到主屏界面

  • 在主屏界面显示 snackbar ,展示选中的项目

1. 创建主屏界面

主屏界面显示一个按钮,当点击按钮时跳转到选择界面。

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

2. 添加按钮,点击时跳转到选择界面

接下来,我们创建 SelectionButton 按钮,它有两个功能:

  • 点击时跳转到选择界面

  • 等待选择界面给它返回结果

  1. class SelectionButton extends StatelessWidget {
  2. @override
  3. Widget build(BuildContext context) {
  4. return RaisedButton(
  5. onPressed: () {
  6. _navigateAndDisplaySelection(context);
  7. },
  8. child: Text('Pick an option, any option!'),
  9. );
  10. }
  11. // 这个方法跳转到选择界面并等待 Navigator.pop 返回 (A method that launches the SelectionScreen and awaits the result from Navigator.pop)
  12. _navigateAndDisplaySelection(BuildContext context) async {
  13. // Navigator.push 方法返回一个 Future 对象并等待,当我们调用 Navigator.pop 时,Future 会完成 (Navigator.push returns a Future that will complete after we call Navigator.pop on the Selection Screen!)
  14. final result = await Navigator.push(
  15. context,
  16. // 在下一步编写 SelectionScreen (We'll create the SelectionScreen in the next step!)
  17. MaterialPageRoute(builder: (context) => SelectionScreen()),
  18. );
  19. }
  20. }

3. 在选择界面显示两个按钮

现在来构建选择界面,它包含两个按钮,当任意一个按钮被点击的时候,关闭选择页面回退到主屏界面,并让主屏界面知道哪个按钮被点击了。

这一步我们来定义 UI,在下一步完成数据的返回。

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

4. 当任意一个按钮被点击,关闭选择界面回退到主屏界面

接下来我们来更新两个按钮的 onPressed 回调函数,使用 Navigator.pop 回退界面并返回数据给主屏界面。

Navigator.pop 方法可以接受第二个参数 result,它是可选的,如果传递了 result,数据将会通过 Future 方法的返回值传递。

Yep 按钮

  1. RaisedButton(
  2. onPressed: () {
  3. // Yep 按钮将返回 "Yep!" 作为结果 (Our Yep button will return "Yep!" as the result)
  4. Navigator.pop(context, 'Yep!');
  5. },
  6. child: Text('Yep!'),
  7. );

Nope 按钮

  1. RaisedButton(
  2. onPressed: () {
  3. // Nope 按钮将返回 "Nope!" 作为结果 (Our Nope button will return "Nope!" as the result)
  4. Navigator.pop(context, 'Nope!');
  5. },
  6. child: Text('Nope!'),
  7. );

5. 在主屏界面显示一个 snackbar,展示选中的项目

现在,我们跳转到选择界面并等待返回结果,当结果返回时我们可以做些事情。

在本例中,我们用一个 snackbar 显示结果,我们来更新 SelectionButton 类中的 _navigateAndDisplaySelection 方法。

  1. _navigateAndDisplaySelection(BuildContext context) async {
  2. final result = await Navigator.push(
  3. context,
  4. MaterialPageRoute(builder: (context) => SelectionScreen()),
  5. );
  6. // 等选择界面返回结果,先隐藏之前的 snackbars,结果显示在新的 snackbars 里 (After the Selection Screen returns a result, hide any previous snackbars and show the new result!)
  7. Scaffold.of(context)
  8. ..removeCurrentSnackBar()
  9. ..showSnackBar(SnackBar(content: Text("$result")));
  10. }

完整代码

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

Returning Data Demo