🕹️
FlutterでBottomNavigationBarを作る
Riverpodで作ってみる
ネットの記事を参考にしたのですが、コードの書き方が古くて、書き直したりしました!
結構大変でしたね。
StatefulWidgetで作る方法は情報が多いのですが、riverpodやProviderで作られた情報は少ないので、今回挑戦して作ってみました!
完成品のソースコード
元になっている公式ドキュメントのコードはこちら
今回使用したStateProviderを使って、UIの状態を監視しています。
enumを操作するのに使っています。
こちらが公式ドキュメント
こちらがサンプルになります
enum型でボタンの種類の定数を作りRiverpodのProviderで状態の変更の監視を行います。
provider/provider.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
// enumは列挙型と呼ばれている固定数の定数値を表すために使用される
// 特別な種類のクラスです。
enum TabType { home, map, profile }
// StateProviderを使用して、enum型のTabTypeを型として使い状態管理をする。
// 初期の状態だとhomeの定数を初期値として使うので、HomeScreenが選択される。
final tabTypeProvider = StateProvider<TabType>((ref) => TabType.home);
今回の参考にさせていただいたコードだと、定数には家、地図、プロフィールのボタンを押すとそれぞれのページへ移動する仕組みになっております。
家のページのコード
screens/home_screen.dart
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(child: Container(child: Text('Home', style: TextStyle(fontSize: 50, color: Colors.blueAccent),))),
);
}
}
地図のページのコード
screens/map_screen.dart
import 'package:flutter/material.dart';
class MapScreen extends StatelessWidget {
const MapScreen({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Map'),
),
body: Center(child: Container(child: Text('Map', style: TextStyle(fontSize: 50, color: Colors.green),))),
);
}
}
プロフィールのページのコード
screens/profile_screen.dart
import 'package:flutter/material.dart';
class ProfileScreen extends StatelessWidget {
const ProfileScreen({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ProfileScreen'),
),
body: Center(child: Container(child: Text('ProfileScreen', style: TextStyle(fontSize: 50, color: Colors.orange),))),
);
}
}
BottomNavigationBarを操作するコード
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_bottom_navigation/provider/provider.dart';
import 'package:riverpod_bottom_navigation/screens/home_screen.dart';
import 'package:riverpod_bottom_navigation/screens/map_screen.dart';
import 'package:riverpod_bottom_navigation/screens/profile_screen.dart';
void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
// ThemeDataでAppBar全体の色を統一する!
theme: ThemeData(
// 16進数の色を使うときは、Color(0xffの後に16進数の色を使用する)
appBarTheme: const AppBarTheme(color: Color(0xff62abf5)),
),
title: 'app',
home: ScreenContainer(),
debugShowCheckedModeBanner: false,
);
}
}
class ScreenContainer extends ConsumerWidget {
const ScreenContainer({Key? key}) : super(key: key);
Widget build(BuildContext context, WidgetRef ref) {
// ref.watchで変数の状態の変化を監視する。
final tabType = ref.watch(tabTypeProvider.state);
// List型で画面遷移先のページを定義する。
// 参考にしたコードは、final _screensと書かれていた!
List<Widget> _screens = [
HomeScreen(),
MapScreen(),
ProfileScreen(),
];
return Scaffold(
body: _screens[tabType.state.index],
bottomNavigationBar: BottomNavigationBar(
currentIndex: tabType.state.index,
onTap: (int selectIndex) {
tabType.state = TabType.values[selectIndex];
},
selectedItemColor: Colors.black,
unselectedItemColor: Colors.grey,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'home',
),
BottomNavigationBarItem(
icon: Icon(Icons.map),
label: 'map',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'person',
),
],
),
);
}
}
最後に
BottomNavigationBarを作ってみて、FlutterでListとenumの組み合わせ方と、riverpodの連携をすることを今回学べたので、良いoutputになったと思います!
Discussion