[Flutter] go_router 公式サンプルを動かし、ファイルも分ける

概要

go_router の公式サンプルを動かす。

go_router example | Flutter package
A declarative router for Flutter based on Navigation 2 supporting deep linking, data-driven routes and more

また、機能ごとにファイルを分割する。

以下の環境

  • Flutter 2.8.1
  • go_router 3.0.1

画面遷移ライブラリ gro_router

go_router | Flutter package
A declarative router for Flutter based on Navigation 2 supporting deep linking, data-driven routes and more

Flutter で 画面遷移を実現する方法は複数ある。

  • Navigator ver1
  • Navigator ver2
  • go_router ( Navigator ver2 をラッピング )

今回は go_router を利用する。 Navigator ver2 単体では複雑なところをラッピングしてくれて、簡単に扱えるようになっているため。

なんと有志がドキュメントを日本語化してくれている。

go_router 公式ドキュメント日本語版の目次

チュートリアル

インストール・起動

以下でアプリの雛形作成。

flutter create go_router_sample
cd sample
flutter pub add go_router

公式の Example を lib/main.dart に貼り付け。

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

void main() => runApp(App());

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

  static const title = 'GoRouter Example: Declarative Routes';

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

  final _router = GoRouter(
    routes: [
      GoRoute(
        path: '/',
        builder: (context, state) => const Page1Screen(),
      ),
      GoRoute(
        path: '/page2',
        builder: (context, state) => const Page2Screen(),
      ),
    ],
  );
}

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

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text(App.title)),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () => context.go('/page2'),
                child: const Text('Go to page 2'),
              ),
            ],
          ),
        ),
      );
}

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

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text(App.title)),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () => context.go('/'),
                child: const Text('Go to home page'),
              ),
            ],
          ),
        ),
      );
}

起動確認。

flutter run

初期ページ。「Go to page 2」により2ページ目に遷移する。

2ページ目。「「Go to home page」により、初期ページへ遷移する。

役割ごとにファイル分割

以前カウンターアプリを分割したように、機能ごとにファイルを分割する。

今回は 4 ファイルに分割する。基本、一つのファイルには一つの役割しか持たせないようにする方針。

  • main.dart
  • app.dart
  • page1.dart
  • page2.dart

main.dart

main.dart はアプリを実行するための main 関数のみを記述する。

import 'package:flutter/material.dart';
import 'app.dart';

void main() => runApp(App());

app.dart

app.dart では基となる Widge とルーティングを記述する。

build メソッド内で返す Widget が、 MaterialApp から MaterialApp.router に変更

ページ・機能を呼び出すコントロール部分の認識。ただし、ルーティング機能 ( _router ) は別ファイルに分けていく方針。

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

import 'page1.dart';
import 'page2.dart';

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

  static const title = 'GoRouter Example: Declarative Routes';

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

  final _router = GoRouter(
    routes: [
      GoRoute(
        path: '/',
        builder: (context, state) => const Page1Screen(),
      ),
      GoRoute(
        path: '/page2',
        builder: (context, state) => const Page2Screen(),
      ),
    ],
  );
}

page1.dart

初期ページ。

「onPressed: () => context.go(‘/page2’),」が画面遷移部分。

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

import 'app.dart';

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

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text(App.title)),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () => context.go('/page2'),
                child: const Text('Go to page 2'),
              ),
            ],
          ),
        ),
      );
}

page2.dart

遷移先のページ。

「onPressed: () => context.go(‘/’)」

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

import 'app.dart';

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

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text(App.title)),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () => context.go('/'),
                child: const Text('Go to home page'),
              ),
            ],
          ),
        ),
      );
}

まとめ

今回のサンプルコードはこちら。

GitHub - runble1/flutter_go_router
Contribute to runble1/flutter_go_router development by creating an account on GitHub.

app.dart が大きい。次回は Riverpod を利用して _router を分離していく。

した。

エラー

Because go_router depends on go_router, version solving failed.pub finished with exit code 65

flutter pub add go_router したタイミングで表題のエラー発生。

プロジェクトフォルダ名を「go_router」としていた。

プロジェクトフォルダ名を「go_router_sample」に変更した後、再度 flutter pub add go_router をすると成功。

ライブラリ名とプロジェクトフォルダ名を同名にしてはダメ。

参考

https://gorouter.dev/
Flutter はじめの一歩
はじめに自動的に作られるカウンターアプリを丁寧に解説

コメント

タイトルとURLをコピーしました