AutoRoute BottomNavigationBar
📕Overview
タブナビゲーション
もしあなたがflutter mobileを使っているのであれば、タブナビゲーションを実装する可能性が高いでしょう。
前の例では、入れ子になった子ルートをレンダリングするためにAutoRouterウィジェットを使いましたが、AutoRouterは AutoStackRouterの単なるショートカットです。AutoRouterはAutoStackRouterのショートカットにすぎません。StackRouterは、その内部でページのスタックを管理し、アクティブ/可視ページが常に一番上にあり、その下のページを見るにはそれをポップする必要があります。
タブが変わるたびにネストされたルートをプッシュしたり置き換えたりすることで、AutoRouter(StackRouter) を使ってタブを実装することもできます。
AutoTabsRouterを使えば、オフステージルートの状態を保持したまま異なるルートを切り替えることができ、タブルートはデフォルトで遅延ロードされ(無効にすることも可能)、最終的には好きなトランジションアニメーションを作成することができます。
先ほどの例をタブナビゲーションを使うように変更してみましょう。
ルート宣言マップは何も変更せず、users、posts、settingsの3つのネストした子を持つダッシュボードページがあることに注目してください。
今回は、公式のコードを参考にAutoRoute
でBottomNavigationBarを実装してみましょう!
class DashboardPage extends StatelessWidget {
Widget build(BuildContext context) {
return AutoTabsRouter(
// list of your tab routes
// routes used here must be declared as children
// routes of /dashboard
routes: const [
UsersRoute(),
PostsRoute(),
SettingsRoute(),
],
transitionBuilder: (context,child,animation) => FadeTransition(
opacity: animation,
// the passed child is technically our animated selected-tab page
child: child,
),
builder: (context, child) {
// obtain the scoped TabsRouter controller using context
final tabsRouter = AutoTabsRouter.of(context);
// Here we're building our Scaffold inside of AutoTabsRouter
// to access the tabsRouter controller provided in this context
//
// alternatively, you could use a global key
return Scaffold(
body: child,
bottomNavigationBar: BottomNavigationBar(
currentIndex: tabsRouter.activeIndex,
onTap: (index) {
// here we switch between tabs
tabsRouter.setActiveIndex(index);
},
items: [
BottomNavigationBarItem(label: 'Users', ...),
BottomNavigationBarItem(label: 'Posts', ...),
BottomNavigationBarItem(label: 'Settings', ...),
],
),
);
},
);
}
}
必要なパッケージを追加しておく!
🧷summary
TabをTapすると画面が切り替わるページを3ページ作成しておきます。
1ページ
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
()
class OneScreen extends StatelessWidget {
const OneScreen({super.key});
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text('OneScreen', style: TextStyle(fontSize: 30, color: Colors.red))),
);
}
}
2ページ
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
()
class SecondScreen extends StatelessWidget {
const SecondScreen({super.key});
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text('SecondScreen', style: TextStyle(fontSize: 30, color: Colors.blue))),
);
}
}
3ページ
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
()
class ThreeScreen extends StatelessWidget {
const ThreeScreen({super.key});
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text('ThreeScreen', style: TextStyle(fontSize: 30, color: Colors.green))),
);
}
}
AutoTabsRouter
には、表示したページのクラスを指定する。他のコードは、パッケージのお決まりのコードだと思ってこんな感じで書いてください。MainScreenまで作成したら、build_runnerのコマンドを実行してルートのコードを設定してください。この時点ではまだ画面遷移の設定は終わっていません!
BottomNavigationBarを表示するページ
import 'package:auto_route/auto_route.dart';
import 'package:auto_route_example/root/app_router.gr.dart';
import 'package:flutter/material.dart';
()
class MainScreen extends StatelessWidget {
const MainScreen({super.key});
Widget build(BuildContext context) {
/// [AutoTabsRouter]をビルドし、次のように使用する。
/// ページをレンダリングするための[IndexedStack]を構築する。
return AutoTabsRouter(
routes: const [
OneScreen(),
SecondScreen(),
ThreeScreen(),
],
transitionBuilder: (context, child, animation) {
// 不透明度の遷移を作成します。
return FadeTransition(opacity: animation, child: child);
},
builder: (context, child) {
// 並列ルーティングを処理するルーター・ウィジェットの実装
final tabsRouter = AutoTabsRouter.of(context);
return Scaffold(
body: child,
bottomNavigationBar: BottomNavigationBar(
currentIndex: tabsRouter.activeIndex,
onTap: (value) {
tabsRouter.setActiveIndex(value);
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.feed),
label: 'feed',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
),
],
),
);
},
);
}
}
ページを作成したら、build_runnerのコマンドを実行する。
flutter pub run build_runner build --delete-conflicting-outputs
BottomNavigationBar用のルートを設定すればTabでページを切り替えることができるようになります。
ルートの設定ファイル
import 'package:auto_route/auto_route.dart';
import 'package:auto_route_example/root/app_router.gr.dart';
// flutter pub run build_runner build --delete-conflicting-outputs
(replaceInRouteName: 'Page,Route')
class AppRouter extends $AppRouter {
List<AutoRoute> get routes => [
// BottomNavigationBar用のルーティングを指定する
AutoRoute(page: MainScreen.page,
initial: true,
// childrenにはTabBarのページを指定する
children: [
AutoRoute(page: OneScreen.page),
AutoRoute(page: SecondScreen.page),
AutoRoute(page: ThreeScreen.page),
],
)
];
}
main.dart
をauto_route
対応のコードに修正する。
main.dartの設定
import 'package:auto_route_example/root/app_router.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({super.key});
final _appRouter = AppRouter(); // auto_routeのrouterを追加
Widget build(BuildContext context) {
return MaterialApp.router( // MaterialApp.routerに変更
routerConfig: _appRouter.config(), // auto_routeのrouterを追加
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
);
}
}
TabをTapするとこんな感じでページが切り替わります。
🧑🎓thoughts
今回は、auto_route
でBottomNavigationBarを使ってみました。go_router
が公式だから良い、安心だと思われているようですが、ルートを自動生成してくれたりtype safeに扱えるだとかで人気ある画面遷移のパッケージなので、ご興味ある方は使ってみてください💙💚
参考になった動画:
Discussion
2024/10/12
routeのクラスの設定方法が変わったようです。
9.0.0 [Breaking Changes]
BREAKING CHANGE: No Router class will be generated anymore. Instead, you extend RootStackRouter from the auto_route package.
BREAKING CHANGE: Providing return types inside @RoutePage<Type>() is no longer needed. you just provide the type as you push the page.
BREAKING CHANGE: Providing a global route is now done by overriding the guards property inside the router. implementing AutoRouteGuard is no longer supported.
BREAKING CHANGE: AutoRouterConfig.module is removed as it's no longer needed. PageRouteInfos are now self-contained.
For more info read the complete migration guide Migrating to v9
FIX: Fix Aliased types are not generated correctly.
FEAT: You can now create empty shell routes like follows
変更点: Routerクラスは生成されなくなりました。代わりに、auto_routeパッケージからRootStackRouterを拡張します。
変更: @RoutePage<Type>()内で戻り値の型を提供する必要がなくなりました。
BREAKING CHANGE: グローバルルートの提供は、ルーター内のガードプロパティをオーバーライドすることで行われるようになりました。
変更: AutoRouterConfig.moduleは不要になったので削除されました。PageRouteInfosは自己完結型になりました。
詳しくは完全な移行ガイドをお読みください。
修正: エイリアス型が正しく生成されない問題を修正。
機能: 以下のように空のシェルルートを作成できるようになった。
変更前
変更後