酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

flutter で go_router を使って画面遷移する

注意:go_router は現在更新頻度が高くバージョンアップも頻繁におこなわれています。この記事は go_router v3.x時代に書かれたもののため、現行の go_router では動かない可能性があります。ご注意ください。

flutter での画面遷移に躓いたので「flutterでの画面遷移方法がわからない」で色々試した。画面遷移ライブラリはたくさんあるようだが、現状では go_router についての情報が一番多かったので、右に倣えで私も go_router を使うことにした。

go_router のインストール

pubspec.yaml に go_router を追加した。バージョン情報には何を指定すれば良いのかわからないので「go_router | Flutter Package」をコピペした。

dependencies:
  flutter:
    sdk: flutter
  go_router: ^3.1.1

画面を定義する

サンプルアプリでは下図の画面遷移を想定している。設定画面から詳細画面へ遷移する理由については(あまり考えてないが)購入履歴画面から該当の商品ページへ遷移しているイメージである。

サンプルアプリの画面遷移図

Appクラスの定義は以下の通りとした。

class App extends StatelessWidget {
  App({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) => MaterialApp.router(
    routeInformationParser: _router.routeInformationParser,
    routerDelegate: _router.routerDelegate,
    title: 'ptcgscore',
  );

  final GoRouter _router = GoRouter(
    routes: <GoRoute>[
      GoRoute(
          name: "home",
          path: '/',
          builder: (BuildContext context, GoRouterState state) =>
            const HomeScreen(title: 'ホーム')
          ,
          routes: [
            GoRoute(
              name: "settings",
              path: 'settings',
              pageBuilder: (context, state) => const MaterialPage(
                fullscreenDialog: true,
                child: SettingsScreen(),
              ),
            ),
            GoRoute(
                name: "detail",
                path: "detail/:pid",
                builder: (BuildContext context, GoRouterState state) {
                  final String id = state.params['pid']!;
                  return DetailScreen(pid: id);
                }
            )
          ]
      ),
    ],
  );
}

ホーム画面から詳細画面へ遷移する

HomeScreen から DetailScreen へ遷移する時、iOS でいうところの右から左にスライドしてくるプッシュ的なトランジションで移動したい。この場合の説明をする。

ホーム画面のフロートボタンをタップした際に context.go('/detail/1'); を実行して遷移する。

// ... (省略)
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 詳細画面へ遷移する
          context.go('/detail/1');
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

ホーム画面から設定画面へ遷移する

HomeScreen から SettingsScreen へ遷移する時、iOS でいうところの下から上に画面が生えてくるモーダル的なトランジションで移動したい。この場合の説明をする。

ホーム画面のアクションバー上の設定ボタンをタップした際に context.go('/settings'); を実行して遷移する。

    return Scaffold(
      appBar: AppBar(
          title: Text(widget.title),
          actions: [
            IconButton(
              icon: const Icon(Icons.settings),
              tooltip: '設定',
              onPressed: () {
                // 設定画面へ遷移する
                context.go('/settings');
              },
            )
          ],
      ),
// ... (省略)

余談だがネイティブのiOSアプリと比べると下から上に画面が生えてくるトランジションに少し違和感があるように思える。pageSheet的な半モーダル表示にはできなさそうである (要調査)。

設定画面から詳細画面へ遷移する

SettingsScreen から DetailScreen へ遷移する時、iOS でいうところのプッシュ的なトランジションで移動したい。ただし、設定画面と詳細画面はパスが /settings/detail/:pid といったように同列に位置している。前述した context.go() を使う方法では画面遷移が壊れてしまう。この場合の説明をする。

設定画面と詳細画面は同列なので context.go() ではなく context.push()を使うことで、App#_router で定義した画面の親子関係を無視して画面遷移できる。

// ... (省略)
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 設定画面と詳細画面は同列なので go ではなく pushを使う。
          context.push('/detail/2');
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

遷移スタックがきちんと管理されているので、ブラウザで実行した際に戻るボタンを押しても適切にホーム画面に戻ることができる。