go_router: 導入 使い方 - Ki-Kobayashi/flutter_wiki GitHub Wiki

🟩 導入

fvm flutter pub add go_router

dependencies:
  flutter:
    sdk: flutter

  ・・・
  go_router: ^10.2.0

.

🟩必要な設定

💎新規作成クラス一覧(config/router/ココ)

  • app_router.dart
  • route_path.dart

💎編集クラス一覧

  • application.dart

.

🟡 【新規】app_router.dart

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:weather_riverpod_prac/config/router/route_path.dart';

final routerProvider = Provider((ref) {
  final rootNavigatorKey = GlobalKey<NavigatorState>(debugLabel: 'root');
  final tabHomeNavigatorKey = GlobalKey<NavigatorState>(debugLabel: 'tabHome');
  final tabSearchNavigatorKey =
      GlobalKey<NavigatorState>(debugLabel: 'tabSearch');
  final tabMainNavigatorKey =
      GlobalKey<NavigatorState>(debugLabel: 'tabMain');
  final tabNoticeNavigatorKey =
      GlobalKey<NavigatorState>(debugLabel: 'tabNotice');
  final tabAccountNavigatorKey =
      GlobalKey<NavigatorState>(debugLabel: 'tabAccount');

  final isLoggedIn = ref.watch(authControllerProvider
          .select((state) => state.valueOrNull?.isLoggedIn)) ??
      false;

  return GoRouter(
    navigatorKey: rootNavigatorKey,
    debugLogDiagnostics: kDebugMode,
    // アプリが起動した時
    initialLocation: isLoggedIn ? IndexPage.path : StartPage.path,
    observers: [
      ref.watch(routeObserverProvider),
    ],
    routes: <RouteBase>[
      GoRoute(
        path: StartPage.path,
        name: StartPage.pathName,
        builder: (BuildContext context, GoRouterState state) {
          return const StartPage();
        },
      ),
      GoRoute(
        parentNavigatorKey: rootNavigatorKey,
        path: SignUpPage.path,
        name: SignUpPage.pathName,
        builder: (BuildContext context, GoRouterState state) {
          return SignUpPage();
        },
      ),
      GoRoute(
        parentNavigatorKey: rootNavigatorKey,
        path: LoggedInPage.path,
        name: LoggedInPage.pathName,
        builder: (BuildContext context, GoRouterState state) {
          return LoggedInPage();
        },
      ),
   // 💡ボトムナビの状態保持してくれるやつ
      StatefulShellRoute.indexedStack(
        parentNavigatorKey: rootNavigatorKey,
        builder: (context, state, navigationShell) {
          return IndexPage(
            navigationShell: navigationShell,
          );
        },
        branches: [
          StatefulShellBranch(
            navigatorKey: tabHomeNavigatorKey,
            routes: <RouteBase>[
              GoRoute(
                path: HomePage.path,
                name: HomePage.pathName,
                builder: (context, state) {
                  return HomePage();
                },
              ),
            ],
          ),
          StatefulShellBranch(
            navigatorKey: tabSearchNavigatorKey,
            routes: <RouteBase>[
              GoRoute(
                path: SearchPage.path,
                name: SearchPage.pathName,
                builder: (context, state) => const SearchPage()
              ),
            ],
          ),
          StatefulShellBranch(
            navigatorKey: tabMainNavigatorKey,
            routes: <RouteBase>[
              GoRoute(
                path: MainPage.path,
                name: MainPage.pathName,
                builder: (context, state) => isLoggedIn
                    ? const MainPage()
                    : LoginPage(),
              ),
            ],
          ),
          StatefulShellBranch(
            navigatorKey: tabNoticeNavigatorKey,
            routes: <RouteBase>[
              GoRoute(
                path: NoticePage.path,
                name: NoticePage.pathName,
                // お知らせタブ:既読・未読処理があるためログイン確認が必要
                builder: (context, state) => const NoticePage(),
                routes: <RouteBase>[
                  GoRoute(
                    path: NoticeDetailPage.path,
                    name: NoticeDetailPage.pathName,
                    builder: (context, state) {
                      // 💡値の受け取り
                      final noticeInfo = state.extra as NoticeInfo;
                      return NoticeDetailPage(notice: noticeInfo);
                    },
                  ),
                ],
              ),
            ],
          ),
          StatefulShellBranch(
            navigatorKey: tabAccountNavigatorKey,
            routes: <RouteBase>[
              GoRoute(
                path: AccountSettingPage.path,
                name: AccountSettingPage.pathName,
                builder: (context, state) => const AccountSettingPage(),
                routes: <RouteBase>[
                  GoRoute(
                    path: APage.path,
                    name: APage.pathName,
                    builder: (context, state) {
                      return const APage();
                    },
                  ),
                  GoRoute(
                    path: BPage.path,
                    name: BPage.pathName,
                    builder: (context, state) {
                      return BPage();
                    },
                  ),
                ],
              ),
            ],
          ),
        ],
      ),
      GoRoute(
        parentNavigatorKey: rootNavigatorKey,
        path: ItemDetailPage.path,
        name: ItemDetailPage.pathName,
        builder: (context, state) {
          final itemId = state.extra ?? ''  as String;
          return ItemDetailPage(itemId: itemId);
        },
      ),
    ],
  );
});

.

🟡 【新規】route_path.dart

class RoutePath {
  static const String top = '/';
  static const String itemList = '/items';
  static const String itemDetail = '/items/detail'; 
  ・・・

}

.

🟡【追記】application.dart

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

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final goRouter = ref.watch(routerProvider); 👈追加

    return MaterialApp.router(
      debugShowCheckedModeBanner: false, // デバッグラベルの非表示
      routerConfig: goRouter, 👈追加
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      // home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

.

🟩 状態保持のボトムナビゲーション

AppRouter.dartと併せて、以下を設定する

🟡 ボトムナビゲーション配置Widget

class IndexPageextends StatelessWidget {
  const IndexPage({
    super.key,
    required this.navigationShell,
  });
  static const path = '/';
  static const pathName = 'index';

  final StatefulNavigationShell navigationShell;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      behavior: HitTestBehavior.opaque,
      onTap: () => primaryFocus?.unfocus(),
      onLongPress: () => primaryFocus?.unfocus(),
      child: Scaffold(
        appBar: navigationShell.currentIndex == 0
            ? const SearchAppbar()
            : null,
        body: WillPopScope(
          onWillPop: () async {
            return false;
          },
          child: SafeArea(
            child: navigationShell,
          ),
        ),
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: navigationShell.currentIndex,
          onTap: (index) => _goBranch(index),
          items: <BottomNavigationBarItem>[
            BottomNavigationBarItem(
              activeIcon: _tabIcon('assets/images/tab_active_xxx.png'),
              icon: _tabIcon('assets/images/tab_xxx.png'),
              label: 'AAA',
            ),
            BottomNavigationBarItem(
              activeIcon: _tabIcon('assets/images/tab_active_xxx.png'),
              icon: _tabIcon('assets/images/tab_xxx.png'),
              label: 'AAA',
            ),
            BottomNavigationBarItem(
              activeIcon: _tabIcon('assets/images/tab_active_xxx.png'),
              icon: _tabIcon('assets/images/tab_xxx.png'),
              label: 'AAA',
            ),
            BottomNavigationBarItem(
              activeIcon: _tabIcon('assets/images/tab_active_xxx.png'),
              icon: _tabIcon('assets/images/tab_xxx.png'),
              label: 'AAA',
            ),
            BottomNavigationBarItem(
              activeIcon: _tabIcon('assets/images/tab_active_xxx.png'),
              icon: _tabIcon('assets/images/tab_xxx.png'),
              label: '',
            ),
          ],
          type: BottomNavigationBarType.fixed,
        ),
      ),
    );
  }

  SizedBox _tabIcon(String path) {
    return SizedBox(
      height: 40.0,
      width: 50.0,
      child: Image.asset(path),
    );
  }

  void _goBranch(int index) {
    navigationShell.goBranch(
      index,
      initialLocation: index == navigationShell.currentIndex,
    );
  }
}

.

🟩

🟡

.

🟩

🟡

.

🟩

🟡

.

🟩

🟡

.

🟩

🟡

.

⚠️ **GitHub.com Fallback** ⚠️