[基礎知識]画面遷移を実現するパッケージ/go_router

go_router は、Googleが開発したパッケージで、シンプルで強力なルーティングシステムを提供し、Flutterアプリケーションの開発を効率的に進めるための優れたツールです。
特にURLベースのナビゲーションを必要とする場合や、Flutter Webとの統合を考慮する場合に非常に有用です。

1.サンプル(動作)

以下は、(前回記事と同じ仕様ですが)2つの画面(PageA画面(page_a.dart)、PageB画面(page_b.dart))を用意し、相互の画面遷移を行うサンプルです。

①PageA画面で、ElevatedButton「Go to PageB」をクリックします。

②するとPageB画面に遷移します。
 ここで、ElevatedButton「Go to PageA」をクリックします。

③するとPageA画面に遷移し(戻り)ます。

2.サンプル(コード)

2ー1.ファイルの配置

各ファイルを以下の様に配置することとします。

lib/
  ├── main.dart
  ├── page_a.dart
  └── page_b.dart

2ー2.各ファイルのコード

(1)main.dart

Dart
// main.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';  // go_routerパッケージをインポート

import 'page_a.dart'; // PageAを定義したファイルをインポート
import 'page_b.dart'; // PageBを定義したファイルをインポート

void main() {
  runApp(MyApp());  // アプリケーションを実行するエントリーポイント
}

class MyApp extends StatelessWidget {
  // GoRouterインスタンスを作成し、ルートを設定
  final GoRouter _router = GoRouter(
    // ルートの定義:
    routes: [
      // '/'パスに対応するウィジェットをPageAに設定
      GoRoute(
        path: '/',
        builder: (context, state) => const PageA(),
      ),
      // '/pageB'パスに対応するウィジェットをPageBに設定
      GoRoute(
        path: '/pageB',
        builder: (context, state) => const PageB(),
      ),
    ],
  );

  MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    // MaterialApp.routerを使って、go_routerのルーティング機能を設定
    return MaterialApp.router(
      // ルーターのデリゲート
      routerDelegate: _router.routerDelegate,
      // ルート情報のパーサー
      routeInformationParser: _router.routeInformationParser,
      // ルート情報のプロバイダー
      routeInformationProvider: _router.routeInformationProvider,
    );
  }
}

(2)page_a.dart

Dart
// page_a.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';  // go_routerパッケージをインポート

class PageA extends StatelessWidget {
  const PageA({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Page A')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            context.go('/pageB');  // ボタンを押したときに、/pageBパスに遷移
          },
          child: const Text('Go to Page B'),
        ),
      ),
    );
  }
}

(3)page_b.dart

Dart
// page_b.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';  // go_routerパッケージをインポート

class PageB extends StatelessWidget {
  const PageB({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Page B')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            context.go('/');  // ボタンを押したときに、/パスに遷移
          },
          child: const Text('Go to Page A'),
        ),
      ),
    );
  }
}

3.総括(処理の流れ)

上記の画面遷移処理は、以下の様な流れで処理されています。

(1) 初期画面の表示(main.dart → page_a.dart)

  • アプリケーションが起動後、エントリーポイントが実行されます。
    runApp関数が呼び出され、MyAppウィジェットがアプリケーションのルートとして設定されます。
  • MyAppウィジェットの構築
    MyAppクラスのコンストラクタが呼び出され、GoRouterインスタンスが作成されます。
     このインスタンスは、アプリケーションのルートを管理します。
    GoRouterroutesプロパティで、/パスと/pageBパスに対応する画面を設定します。
    MaterialApp.routerウィジェットで、go_routerのルーティング機能をアプリケーションに組み込みます。
Dart
// main.dart
class MyApp extends StatelessWidget {
  // GoRouterインスタンスを作成し、ルートを設定
  <mark style="background-color:#fcb900" class="has-inline-color">final <strong>GoRouter</strong> _router = GoRouter(</mark>
    // ルートの定義:
    <mark style="background-color:#f78da7" class="has-inline-color"><strong>routes: [</strong></mark>
      // '/'パスに対応するウィジェットをPageAに設定
      <mark style="background-color:#f78da7" class="has-inline-color"><strong>GoRoute(</strong></mark>
        <mark style="background-color:#f78da7" class="has-inline-color">path: '/',</mark>
        builder: (context, state) => <strong><mark style="background-color:#f78da7" class="has-inline-color">const PageA()</mark></strong>,
      ),
      // '/pageB'パスに対応するウィジェットをPageBに設定
      <strong><mark style="background-color:#f78da7" class="has-inline-color">GoRoute(</mark></strong>
        <mark style="background-color:#f78da7" class="has-inline-color">path: '/pageB',</mark>
        builder: (context, state) => <strong><mark style="background-color:#f78da7" class="has-inline-color">const PageB()</mark></strong>,
      ),
    <mark style="background-color:#f78da7" class="has-inline-color">],</mark>
  <mark style="background-color:#fcb900" class="has-inline-color">);</mark>
  • (上記により)GoRouterにより初期ルートが評価され、/パスに対応するPageAが表示されます。
Dart
// page_a.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';  // go_routerパッケージをインポート

class <strong><mark style="background-color:#fcb900" class="has-inline-color">PageA</mark></strong> extends StatelessWidget {
  const PageA({super.key});
}

(2)画面遷移の実行(page_a.dart → page_b.dart)

  • ユーザーがボタンを押すと、context.go('/pageB')が呼び出されGoRouter/pageBパスに対応する画面を表示します。
Dart
onPressed: () {
  <strong><mark style="background-color:#fcb900" class="has-inline-color">context.go('/pageB');</mark></strong>  // ページBへの遷移
}

(3)遷移後の画面の表示(page_b.dart)

  • /pageBパスに対応するPageBが表示されます。
  • PageBウィジェットが表示され、ユーザーが操作できる状態になります。
  • ユーザーが「Go to Page A」ボタンを押すと、context.go('/')が呼び出されます。
Dart
// page_b.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';  // go_routerパッケージをインポート

class PageB extends StatelessWidget {
  const PageB({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Page B')),
      body: Center(
        child: ElevatedButton(
          <mark style="background-color:#fcb900" class="has-inline-color">onPressed: () {</mark>
            <mark style="background-color:#fcb900" class="has-inline-color">context.go('/');</mark>  // ボタンを押したときに、/パスに遷移
          <mark style="background-color:#fcb900" class="has-inline-color">},</mark>
          child: const Text('Go to Page A'),
        ),
      ),
    );
  }
}

4.まとめ

  • アプリケーション起動時にmain.dartmain関数が実行され、MyAppウィジェットが表示される。
  • MyAppウィジェット内でGoRouterが初期化され、ルート設定が行われる。
  • 初期画面としてPageAが表示される。
  • ユーザーがPageAのボタンを押すと、context.go('/pageB')が呼び出され、PageBに遷移する。
  • PageBが表示され、ユーザーがPageBのボタンを押すと、context.go('/')が呼び出され、再びPageAに遷移する。

この流れにより、go_routerを使ったシンプルな画面遷移の処理を理解できます。

コメントを残す