画面名を使った画面遷移
ここまでは、画面ウィジェットを直接指定して遷移するプログラムを記述していましたが、画面名を用いて画面遷移することも可能です。画面名で用いることで、画面が多くなっても把握しやすくなります。また、指定した画面まで戻る場合には画面名があるので、より簡単にプログラムができます。
Named Routes(名前での画面遷移)
画面名と実際の画面ウィジェットの管理はリスト5のようにMaterialApp上で行います。
class MyApp3 extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( :(省略) // (1) 最初のページ名 initialRoute: '/first', // (2) ページ名とウィジェットの関係 routes: { '/first' : (context) => FirstPage(), '/second' : (context) => SecondPage(), '/args' : (context) => ArgsPage(), } ); } }
initialRouteプロパティ(1)は起動したときの最初の画面名を指定し、routesプロパティ(2)で各画面名と画面ウィジェットを指定します。また、画面遷移する際にはリスト6のようなメソッドが主に用意されています。
// (1) 指定した画面に遷移する Navigator.pushNamed(context, '/second'); // (2) 指定した画面と置き換える Navigator.pushReplacementNamed(context, '/second'); // (3) 指定した画面(ここでは/first)まで削除した上で、指定した画面(ここでは/second)に遷移する Navigator.pushNamedAndRemoveUntil(context, '/second',ModalRoute.withName('/first')); // (4) 指定した画面まで戻る Navigator.popUntil(context, ModalRoute.withName('/first'));
Named Routesを使った場合には、Routeインスタンスを指定する必要がなく、(1)(2)(3)のようにメソッド名にNamedが付与されたメソッドでより簡単に画面遷移が可能です。
また、(3)pushNamedAndRemoveUntilは、指定した画面まで戻った上で、新規に画面を追加するための処理です。
実は、名前を使わないpushAndRemoveUntilというメソッドもリスト7のように利用できます。しかし、popUntilと同様にNamed Routesを使わない場合に、どこまでという指定が難しいため、使いにくい部分があります。
onPressed: (){ Navigator.pushAndRemoveUntil(context, MaterialPageRoute( builder: (context) => new ThirdPage() ),(route) => route.isFirst); }
一方、Named Routesを使えば、名前が指定できるので、複雑な画面遷移も作りやすくなっています。例えば、どの画面まで戻るかということが簡単に指定でき、ウィザード形式のような画面遷移を作りやすくなります。
同様にpopUntil(4)メソッドでも画面名が指定できるので、使いやすくなります。また、pushNamedAndRemoveUntil/popUntilでは、厳密には画面名を指定しているのではなく、一致するRouteインスタンスを判断するための関数を指定しています。ModalRouteのwithNameメソッドを使うことで簡単に利用することが可能です。
遷移先の画面にデータを渡す場合
画面遷移する際に、データと共に画面遷移したい場合があります。Named Routesを使わない場合には、インスタンス作成時にデータを渡せばよかったのですが、Named Routesでは画面ウィジェットのインスタンスを作成するコードがないので、指定できません。その場合、リスト8のように行います。
// (1) 引数の型(lib/sample3/ArgPage.dartの抜粋) class PageArguments{ final String message; PageArguments(this.message); } // (2) ページ遷移する側のコード(lib/sample3/SecondPage.dartの抜粋) Navigator.pushNamed(context, "/args",arguments: PageArguments("こんにちは!")); // (3) 引数を必要とする画面ウィジェット(lib/sample3/ArgPage.dartの抜粋) class ArgsPage extends StatelessWidget{ @override Widget build(BuildContext context) { // (4) ページ側で引数を受け取る場合のコード final PageArguments args = ModalRoute.of(context).settings.arguments as PageArguments; print(args.message); } }
(1)は次の画面に渡すデータ型です。特にデータ型に制限はありません。そのため、文字列だけ等であれば必要ありません。(2)は、"/args"で指定された画面に、argumentsで指定したデータを渡して画面遷移します。データを受け取る画面ウィジェットは(3)のように特別なウィジェットとして作成する必要はありません。そして、送信されたデータは、(4)のように、ModalRouteのofメソッドを使って、[RouteSettings[https://api.flutter.dev/flutter/widgets/RouteSettings-class.html]オブジェクトのargumentsプロパティから取得可能です。
画面名を使った一覧と詳細画面の応用
MaterialAppのroutesプロパティで対応する画面ウィジェットを指定する代わりに、onGenerateRouteにメソッドを利用することで、動的な名前に対応することができます。この仕組みを利用して、図6のようにWebアプリのようなPATHパラメータのような仕組みを作ることが可能です。
リスト9は、MaterialAppに図6のようなルールで画面遷移するようにするためのonGenerateRouteの実装例です。
class MyApp4 extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( // :(省略) initialRoute: '/', // (1) 画面が切り替わったときに呼ばれるコールバック処理 onGenerateRoute: (RouteSettings settings){ // (2) 最初のページを返す if(settings.name == '/'){ return MaterialPageRoute( builder: (context) => ListPage() ); } // (3) /detail/{id} のようなページ名の場合 var uri = Uri.parse(settings.name); var id = uri.pathSegments[1]; return MaterialPageRoute( builder: (context) { return ItemPage( id : id ); }, ); return null; } ); } }
onGenerateRoute(1)が、pushNamed等が実行されたときにコールされます。実際に呼ばれた画面名はsettings.nameプロパティ(2)に設定されています。アプリの起動時には"/"が最初の画面名として指定されるので、まず一覧画面を表示します。そして、一覧ページからは、"/detail/3"のような名前が呼ばれるため、その名前をURLとして扱い、2番目のパスに相当する数字データを取得し、詳細ページに引数として設定します。また、一覧ページ側のコードを示してものがリスト10です。
// (1) 一覧に表示するデータ用のクラス class ListItem{ final int id; ListItem(this.id); } class ListPage extends StatelessWidget{ @override Widget build(BuildContext context) { // (2) データ一覧 Listitems = [ ListItem(1), :(省略) ListItem(6) ]; return Scaffold( //(省略) body: ListView( children: [ for(var item in items) ListTile( title: Text("Item is ${item.id}"), onTap: () => { // (3) 詳細ページへ画面遷移 Navigator.pushNamed(context, "/detail/${item.id}") }, ) ], ), ); } }
(1)は、一覧に表示するためのデータ用のクラスです。そして、一覧に表示するためのデータリストを(2)のように作成しています。実際にはサーバ側にあるデータなどをAPIで取得するような形が多いとは思います。そして、そのデータのidを使って画面遷移する部分が(3)になります。
このようにすることで、引数を渡して画面遷移することと同様のことが行えます。また、こういった手法はWebアプリではよく行う手法の1つでもあるため、画面遷移のルールを定義しやすいというメリットもあります。
まとめ
今回、紹介した画面遷移方法は画面の状態や可能な遷移先もすべてプログラマが命令するような画面遷移スタイルでした。そして、onGenerateRouteを活用することで、より柔軟な画面遷移へと応用できることも示しました。
次回は、Flutter2での新しい画面遷移であるNavigator 2.0を紹介します。これは、WebアプリのようにURLの変更などにより画面遷移への対応なども含んでいます。そのため、スマホアプリ開発のみを考えた場合には少々難解になります。