【Flutter】NavigationBarを使って各画面を呼び出してみる

実装した画面のイメージ
流れはNavigationBarから各画面のファイルを呼び出して表示しています。

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480691/459a6a47-b7aa-08b8-aa1a-cb5b9d598b3b.gif">

## 環境
- MacOS：13.3
- Flutter：3.19.1
## ディレクトリ構成
NavigationBarから各画面のファイルを呼び出せるように構成。
```
lib
├── src
│   ├── screens
│   │   ├── home.dart # ホーム画面
│   │   ├── map.dart # マップ画面
│   │   ├── setting.dart # 設定画面
│   └── app.dart # ナビゲーションの実装
└── main.dart
```
## 実装
まずは各画面を実装をします。
中身としてはappbarとbodyに画面名を表示しています。

**ホーム画面**
```lib/src/screens/home.dart
import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Home'),
      ),
      body: const Center(
          child: Text('Home画面', style: TextStyle(fontSize: 32.0))
      ),
    );
  }
}
```
**マップ画面**
```lib/src/screens/map.dart
import 'package:flutter/material.dart';

class MapScreen extends StatelessWidget {
  const MapScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Map'),
      ),
      body: const Center(
          child: Text('Map画面', style: TextStyle(fontSize: 32.0))),
    );
  }
}
```
**設定画面**
```lib/src/screens/setting.dart
import 'package:flutter/material.dart';

class SettingScreen extends StatelessWidget {
  const SettingScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Setting'),
      ),
      body: const Center(
          child: Text('Setting画面', style: TextStyle(fontSize: 32.0))),
    );
  }
}
```
続いてNavigationBarを使って、最初に実装した各画面を表示します。

BottomNavigationはStatefulWidgetのクラスです。
Statefulってなんぞやという方はこちらへ。
https://flutter.ctrnost.com/tutorial/tutorial05/
```lib/src/app.dart
import 'package:flutter/material.dart';
import 'screens/home.dart';
import 'screens/map.dart';
import 'screens/setting.dart';

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      // Flutter公式サイトThemeを設定
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      // NavigaionBarのClassを呼び出す
      home: const BottomNavigation(),
    );
  }
}

class BottomNavigation extends StatefulWidget {
  const BottomNavigation({super.key});

  @override
  State<BottomNavigation> createState() => _BottomNavigationState();
}

class _BottomNavigationState extends State<BottomNavigation> {
  // 各画面のリスト
  static const _screens = [
    HomeScreen(),
    MapScreen(),
    SettingScreen()
  ];
  // 選択されている画面のインデックス
  int _selectedIndex = 0;

  @override
  Widget build(BuildContext context) {
    final ThemeData theme = Theme.of(context);
    return Scaffold(
      body: _screens[_selectedIndex],
      // 本題のNavigationBar
      bottomNavigationBar: NavigationBar(
        // タップされたタブのインデックスを設定（タブ毎に画面の切り替えをする）
        onDestinationSelected: (int index) {
          setState(() {
            _selectedIndex = index;
          });
        },
        // 選択されているタブの色（公式サイトのまま黄色）
        indicatorColor: Colors.amber,
        // 選択されたタブの設定（設定しないと画面は切り替わってもタブの色は変わらないです）
        selectedIndex: _selectedIndex,
        // タブ自体の設定（必須項目のため、書かないとエラーになります）
        destinations: const <Widget>[
          NavigationDestination(
            selectedIcon: Icon(Icons.home),
            icon: Icon(Icons.home_outlined),
            label: 'Home',
          ),
          NavigationDestination(
            icon: Icon(Icons.map),
            label: 'Map',
          ),
          NavigationDestination(
            icon: Icon(Icons.settings),
            label: 'Settings',
          ),
        ],
      )
    );
  }
}
```
最後にアプリを表示するためにmain()からMyapp()を呼び出します。
```lib/main.dart
import 'package:flutter/material.dart';
import 'src/app.dart';

void main() {
  runApp(const MyApp());
}
```
## まとめ
Flutterで何か作るために、とりあえずアプリのガワを作ろう。
そして今回はBottomタブと画面の切り替えをできるようにしました。
元々は`BottomNavigationBar`を使おうと思っていましたが、新しくMaterial3のデザイン用に`NavigationBar`が登場したようなので、こちらを採用してみました。

## 参考文献

https://api.flutter.dev/flutter/material/NavigationBar-class.html

https://dev.classmethod.jp/articles/flutter-bottom-navigation/

https://zenn.dev/urasan/articles/e9b18c47d1747d