[Flutter] 名前付きルートに引数を渡して画面遷移する際、引数をもとにウィジェットを動的に初期化する方法
前提
原始的な画面遷移
最も原始的な画面遷移の方法は、以下のように Navigator.push()
を使う方法です。
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SomePageWidget(),
),
);
}
名前付きルートを使った画面遷移
画面の数や画面遷移の数がある程度多いアプリになってくると、上記の方法だとコードの重複が気になります。
この問題は以下のように名前付きルートを使うことで解決できます。
MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => FirstPageWidget(),
'/second': (context) => SecondPageWidget(),
'/third': (context) => ThirdPageWidget(title: 'Third page'),
},
);
onPressed: () => Navigator.of(context).pushNamed('/third')
MaterialApp
のコンストラクタ引数でルーティングを定義して、 Navigator.pushNamed()
にルート名を渡すことで画面遷移を行うことができるわけです。便利ですね!
名前付きルートに引数を渡して画面遷移
さて、遷移先のページのウィジェットが引数なしで初期化できる場合や、初期化に必要な引数が定数の場合は、上記の方法で何も問題ありません。
が、今いるページでしか知り得ない情報を引数として渡して次ページのウィジェットを初期化したいような場合は、少し厄介です。
Navigator.push()
を使った原始的な画面遷移だったなら
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SomePageWidget(someDynamicValue),
),
);
}
のようにウィジェットのコンストラクタに直接引数を渡すことができるので何も難しいことはなかったのですが、名前付きルートを使っている場合はこうは行きません。
どうすればいいかというと、 MaterialApp
のコンストラクタ引数 onGenerateRoute
を使います。
具体的には以下のような感じです。
MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => FirstPageWidget(),
'/second': (context) => SecondPageWidget(),
'/third': (context) => ThirdPageWidget(title: 'Third page'),
},
onGenerateRoute: (settings) {
if (settings.name == '/fourth') {
return MaterialPageRoute(
builder: (context) => FourthPageWidget(settings.arguments),
);
}
return null;
},
);
onPressed: () => Navigator.of(context).pushNamed('/fourth', arguments: someDynamicValue)
通常の routes:
を使ったルート定義とは別に、 onGenerateRoute:
のコールバック内でルート名をフックして動的に遷移先ページのウィジェットをビルドする感じです。
コールバックが受け取る settings
の arguments
に、 Navigator.pushNamed()
の引数 arguments
で渡された値が入っています。( arguments
と複数形の名前ですが、特に配列のようなデータ構造を期待しているわけではなく 型は Object
です)
参考:Pass arguments to a named route - Flutter # Alternatively, extract the arguments using onGenerateRoute
参考:FlutterのNavigationとRoutingを理解する
引数で渡された値をただ表示できればいいだけの場合
引数で渡した値をもとに遷移先ページのウィジェットを 初期化 する必要がなくて、単に渡した値を 表示 できればいいだけという場合には、以下のように build()
メソッド内で ModalRoute.settings.arguments
にアクセスすることで渡された引数を受け取ることができます。
class SecondPageWidget extends StatelessWidget {
Widget build(BuildContext context) {
// Navigatorに渡された引数をここで受け取る
final args = ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Text(args['title']),
),
body: Center(
child: Text(args['message']),
),
);
}
}
onPressed: () => Navigator.of(context).pushNamed('/second', arguments: {'title': someDynamicValue1, 'message': someDynamicValue2})
まとめ
- Flutterで名前付きルートに引数を渡して画面遷移する際、引数をもとにウィジェットを動的に生成するには、
MaterialApp
のコンストラクタ引数onGenerateRoute
を使う - ウィジェットの初期化までは不要で単に引数で渡した値を遷移先のページで表示したいだけの場合は、
build()
メソッド内でModalRoute.settings.arguments
から引数を受け取れる
Discussion