Programming Self-Study Notebook

勉強したことを忘れないように! 思い出せるように!!

flutterアプリにルーター機能を追加する


今回は、flutterアプリの画面遷移の制御を集約するルーター機能を追加したいと思います。

使用するパッケージ

  • 以下のパッケージを使用します。
  • 上記リンクのReadmeには細かい使い方の注意が記載されています。

手順

手順1:ルーター機能のパッケージを追加

  • 私はfvmを導入しているので以下のコマンドでパッケージを追加しました。

      fvm flutter pub add go_router
    

コマンド実行結果

(省略)\training_app> fvm flutter pub add go_router
Resolving dependencies...
  flutter_lints 2.0.3 (3.0.1 available)
+ go_router 13.0.1
  js 0.6.7 (0.7.0 available)
  lints 2.1.1 (3.0.0 available)        
+ logging 1.2.0
  matcher 0.12.16 (0.12.16+1 available)
  material_color_utilities 0.5.0 (0.8.0 available)
  meta 1.10.0 (1.11.0 available)
  path 1.8.3 (1.9.0 available)
  test_api 0.6.1 (0.7.0 available)
  web 0.3.0 (0.4.0 available)
Changed 2 dependencies!
9 packages have newer versions incompatible with dependency constraints.
Try `flutter pub outdated` for more information.

手順2:実装

手順2-1:準備

  • ルーターにより画面遷移を実現したいので既存の画面を構成しているWidgetをコピーした別Widgewを作成しておきます。
変更前 コピー リネーム
  • my_widget2.dart及びmy_widget3.dartの中身はmy_widget.dartと区別がつくように適当に変えておいてください。

手順2-2:router.dartを作成する

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:training_app/my_widget.dart';
import 'package:training_app/my_widget2.dart';
import 'package:training_app/my_widget3.dart';

final routerProvider = Provider((ref) => GoRouter(
  initialLocation: '/my_widget',
  routes: [
    GoRoute(
      path: '/my_widget',
      name: 'MyWidget',
      pageBuilder: (context, state) {
        return MaterialPage(
          key: state.pageKey,
          child: MyWidget(),
        );
      },
    ),
    GoRoute(
      path: '/my_widget2',
      name: 'MyWidget2',
      pageBuilder: (context, state) {
        return MaterialPage(
          key: state.pageKey,
          child: MyWidget2(),
        );
      },
    ),
    GoRoute(
      path: '/my_widget3',
      name: 'MyWidget3',
      pageBuilder: (context, state) {
        return MaterialPage(
          key: state.pageKey,
          child: MyWidget3(),
        );
      },
    ),
  ],
  errorPageBuilder: (context, state) => MaterialPage(
    key: state.pageKey,
    child: Scaffold(
      body: Center(
        child: Text(state.error.toString()),
      ),
    ),
  ),
));

手順2-3:main.dartルーターをコールする

import 'package:flutter/material.dart';
import 'package:training_app/my_widget.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:training_app/router.dart';

void main() {
  const app = MyApp();
  const scope = ProviderScope(child: app);
  runApp(scope);
}

class MyApp extends ConsumerWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {

    return MaterialApp.router(
      routerDelegate: ref.watch(routerProvider).routerDelegate,
      routeInformationParser: ref.watch(routerProvider).routeInformationParser,
      routeInformationProvider:
          ref.watch(routerProvider).routeInformationProvider,
      theme: ThemeData(
        useMaterial3: true,
     ),
    );
  }
}

手順2-4:my_widget.dartを修正する

  • 画面遷移のトリガーを作る必要があるので、ドロワーメニューから画面を選択する仕様にしてみました。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';

class MyWidget extends ConsumerWidget {
  const MyWidget({
    super.key,
  });

  @override
  Widget build(BuildContext context, WidgetRef ref) {

    final appBar = AppBar(
        title: const Text('1.タイトル 123456789'),
        centerTitle: true,
        titleSpacing:20,
        titleTextStyle:TextStyle(
          fontSize: 25,
          color: Colors.blueGrey,
          fontWeight: FontWeight.bold,
          fontStyle: FontStyle.italic,
          decoration: TextDecoration.underline,
        ),

        backgroundColor: Color(0xFFa0d8ef),
        flexibleSpace: Container(
          decoration: BoxDecoration(
          image: DecorationImage(
              image: AssetImage('assets/images/appbar/appbar_bg.png'),
              fit: BoxFit.fill),
          ),
        ),

        elevation: 3.0,
        // automaticallyImplyLeading: false,
    );

    final drawer = Drawer(
      child: ListView(
        children: <Widget>[
          DrawerHeader(
            
            decoration: const BoxDecoration(
              color:Color(0xFFa0d8ef),
            ),
            child: Image.asset('assets/images/splash_768x768.png')
            // child: Text('ドロワーヘッダー')
          ),
          ListTile(
            leading: const Icon(Icons.abc),
            title: Text('Drawerを表示'),
            onTap: () {
              context.pop();
              context.push('/my_widget');
            },
          ),
          ListTile(
            leading: const Icon(Icons.access_alarm),
            title: Text('Drawer2を表示'),
            onTap: () {
              context.pop();
              context.push('/my_widget2');
            },
          ),
          ListTile(
            leading: const Icon(Icons.copyright),
            title: Text('Drawer3を表示'),
            onTap: () {
              context.pop();
              context.push('/my_widget3');
            },
          ),
        ],
      ),
    );
    return Scaffold(
      appBar: appBar,
      drawer: drawer,
      body: Container(
        child: Text('Bodyを記載しています。'),
      ),
    );
  }
}
  • my_widget2.dartmy_widget3.dartmy_widget.dartのコピーをベースにしていますが、画面遷移したことが分かるようにクラス名やタイトルなど一部変更しています。

手順2-5:確認

ドロワーメニューを開く 遷移先ページを指定する 画面遷移が実施される

これでルーター機能の実装は終わりです。

最後に

クローンコードが増えてきたので、そろそろコードの整理を実施したいと思います。