Index
ざっくり説明すると、画面遷移を管理する時に便利なパッケージです。
Navigatorの上位互換ですね。
特徴と以下の通り
- テンプレート構文によるパスとクエリパラメータの解析(例:”user/:id”)
- 目的地(副ルート)の画面を複数表示させる
- リダイレクトのサポート – アプリケーションの状態に応じて、ユーザーを別のURLに再ルーティングすることができます(例えば、ユーザーが認証されていない場合のサインインなど)。
- ShellRouteによる複数のNavigatorのサポート – 一致したルートに基づいて、独自のページを表示する内側のNavigatorを表示することができます。例えば、画面の下部に表示されるBottomNavigationBarを表示するには、次のようにします。
- MaterialアプリとCupertinoアプリの両方をサポートします。
- Navigator APIとの後方互換性
詳細は公式のドキュメントをご確認ください。
まずは基本的な使い方から見ていきましょう。
まずは画面遷移を設計します。
例えばこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import 'package:go_router/go_router.dart'; import 'package:goroutersample/pages/page1.dart'; import 'package:goroutersample/pages/page1_detail.dart'; //ここに遷移させたい画面を全部入れていく final GoRouter router = GoRouter( routes: <RouteBase>[ GoRoute(path: '/', builder: (context, state) => const Page1()), GoRoute( path: '/page1/detail', builder: (context, state) => const Page1Deatail()), ], ); |
以下のような形で遷移させたい画面を一つ一つ記述していきます。
HTML
1 |
GoRoute(path:'任意のパス',builder:(context,state) => 任意の画面) |
- 任意のパス:フォルダのディレクトリのような感じで記載していきます。(アプリ起動後に最初に表示したい画面は’/’を指定する)
- 任意の画面:表示させたい画面のwidgetを記載する
go_routerで画面遷移を実装するには以下のコードのようにMaterialApp .routerを記述する必要があります。
色々細かい設定がありますので、公式のドキュメントでご確認ください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { //以下おまじない return MaterialApp.router( routerConfig: router, ); } } |
遷移する画面を作成します。
最初に表示される画面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; class Page1 extends StatelessWidget { const Page1({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: ElevatedButton( onPressed: () => {context.push('/page1/detail')}, child: const Text('next'), ), ), ); } } |
最初のページから遷移する画面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; class Page1Deatail extends StatelessWidget { const Page1Deatail({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Center( child: ElevatedButton( onPressed: () => {context.go('/')}, child: const Text('back page1'), ), ); } } |
画面遷移したいときは以下のように記述します。
HTML
1 |
context.遷移方法('遷移先のパス') |
3つの画面遷移方法
- go(”遷移先のパス) : 遷移先の画面にスタックを置き換える
- push(‘遷移先のパス’) : 現在表示中の画面の上に遷移先の画面をスタックする
- pop() : 一つ前のスタックに戻る
詳細はAPIリファレンスを参照してください。
BottomNavigationBarを使用する際はShellRouter()を使用します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:goroutersample/basepage.dart'; import 'package:goroutersample/pages/home.dart'; import 'package:goroutersample/pages/page1.dart'; import 'package:goroutersample/pages/page1_detail.dart'; import 'package:goroutersample/pages/page2.dart'; import 'package:goroutersample/pages/page2_detail.dart'; //以下の2行はおまじない final GlobalKey<NavigatorState> _rootNavigatorKey = GlobalKey<NavigatorState>(debugLabel: 'root'); final GlobalKey<NavigatorState> _shellNavigatorKey = GlobalKey<NavigatorState>(debugLabel: 'shell'); final GoRouter router = GoRouter( navigatorKey: _rootNavigatorKey, initialLocation: '/', routes: <RouteBase>[ GoRoute( path: '/', builder: (context, state) => const HomePage(), ), //ShellRoute内にBottomNavigationBarで遷移する画面を記載する ShellRoute( navigatorKey: _shellNavigatorKey, //BottomNavigationBarを実装しているページを記載する //childでScaffoldのbodyを渡す builder: (context, state, child) => BasePage( child: child, ), routes: <RouteBase>[ //BottomNavigationBarから遷移するページを記載する GoRoute( path: '/page1', builder: (context, state) => const Page1(), //Page1から遷移するページを記載する routes: <RouteBase>[ GoRoute( path: 'detail', builder: (context, state) => const Page1Deatail(), ), ]), ], ), //BottomNavigationBarから遷移するページを記載する GoRoute( path: '/page2', builder: (context, state) => const Page2(), //Page2から遷移するページを記載する routes: <RouteBase>[ GoRoute( path: 'detail', builder: (context, state) => const Page2Deatail(), ), ], ), ], ); |
最初に表示される画面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; class HomePage extends StatelessWidget { const HomePage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: ElevatedButton( onPressed: (() => context.go('/page1')), child: const Text('go page1'), ), ), ); } } |
以下のようにPush()使用すると純粋なPage1.dartが表示される(BottomNavigationBarが表示されない)ので注意
1 |
context.push('page1') |
BottomNavigationBarの実装
bodyの中身はShellRouteがchildで渡してくれるので、引数で受け取るようにするのがポイント
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; class BasePage extends StatefulWidget { const BasePage({Key? key, required this.child}) : super(key: key); final Widget child; @override State<BasePage> createState() => _BasePageState(); } class _BasePageState extends State<BasePage> { int _selectedIndex = 0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), bottomNavigationBar: NavigationBar( selectedIndex: _selectedIndex, destinations: const <Widget>[ NavigationDestination(icon: Icon(Icons.star), label: 'page1'), NavigationDestination(icon: Icon(Icons.hardware), label: 'page2'), ], onDestinationSelected: (index) { switch (index) { case 0: _selectedIndex = 0; context.push('/page1'); break; case 1: _selectedIndex = 1; context.push('/page2'); break; default: _selectedIndex = 0; context.push('/page1'); } setState(() {}); }, ), body: widget.child, ); } } |
Navigationbarの使い方は以下を参照してください。
[flutter3]NavigationBarの基本的な使い方(サンプルコード付き)Page1の実装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; class Page1 extends StatelessWidget { const Page1({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Center( child: ElevatedButton( onPressed: () => {context.push('/page1/detail')}, child: const Text('go to page1 detail'), ), ); } } |
page1Detailの実装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; class Page1Deatail extends StatelessWidget { const Page1Deatail({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Center( child: ElevatedButton( onPressed: () => {context.pop()}, child: const Text('back page1'), ), ); } } |
Page2,Page2Detailの実装
page1,page1detailと同じため省略