遷移先の画面を終了する時に、元の画面へ何かしらのデータを渡したいというケースがあります。例えば、遷移先の画面で何か選択をした結果を元の画面へ反映したい時などです。
AndroidであればstartActivityForResult
でActivityを起動し、元画面のonActivityResult
でデータを受け取るという感じで実装することができます。
FlutterではNavigator.push
がFuture
を返します。遷移先のNavigator.pop
はこのFuture
をcompleteさせますので、遷移元の画面はFuture
へコールバックを登録しておくことでデータを受け取ることができます。
Flutter公式ドキュメント
Return data from a screen
を元にして実装方法を紹介します。
1. 遷移元画面作成
ボタン押下時に画面遷移させるようにします。
class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text('Returnning Data Demo'), ), body: new Builder( builder: (BuildContext context) { return new Center( child: new RaisedButton( onPressed: () { _navigateAndDisplaySelection(context); }, child: new Text('Pick an option, any option!'), ) ); } ) ); } _navigateAndDisplaySelection(BuildContext context) { Navigator.push(context, new MaterialPageRoute(builder: (context) => new SelectionScreen())) } }
2. 遷移先画面を作成
"Up!"と"Down!"と書かれた2つのボタンを用意します。
class SelectionScreen extends StatelessWidget { @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar(title: new Text('Pick an option'),), body: new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new Padding( padding: const EdgeInsets.all(8.0), child: new RaisedButton( onPressed: () { Navigator.pop(context, 'Up!'); }, child: new Text('Up!'),), ), new Padding( padding: const EdgeInsets.all(8.0), child: new RaisedButton( onPressed: () { Navigator.pop(context, 'Down!'); }, child: new Text('Down!') ) ) ], ) ), ); } }
各ボタン押下時にNavigator.pop
でこの画面を終了する共に、遷移前の画面へ"Up!"と"Down!"の文字列を渡すようにしています。
3. 遷移元画面で値を受け取る
HomeScreen
の_navigateAndDisplaySelection
を以下のように修正します。
_navigateAndDisplaySelection(BuildContext context) { Navigator.push( context, new MaterialPageRoute(builder: (context) => new SelectionScreen()) ).then((result) { Scaffold.of(context).showSnackBar(new SnackBar(content: new Text('$result'))); }); }
前述のようにNavigator.push
はFuture
を返すのでthen
でコールバックを登録することができます。
result
にはNavigator.pop
で渡されたデータが渡ってきてコールバックが実行されます。
ここではSnackBar
でその文字列を表示しています。
async / awaitで書く
then
でコールバック登録するような記述は煩雑になりがちなので、以下のように書くことが多いです。
_navigateAndDisplaySelection(BuildContext context) async { final result = await Navigator.push( context, new MaterialPageRoute(builder: (context) => new SelectionScreen()) ); Scaffold.of(context).showSnackBar(new SnackBar(content: new Text('$result'))); }
Navigator.push
でFuture
が生成されますが、await
によってFuture
がcompleteするまで処理が中断状態になります。前述のようにNavigator.pop
でデータが渡されると処理が再開し、result
にデータが代入され、そのデータでSnackBar
を表示させるという流れになっています。
この辺りのFuture
の扱いに関しては
Asynchronous Programming: Futures
が参考になるかと思います。
最後に、AndroidとiOSでビルドすると以下のようになります。
Android | iOS |
---|---|