Flutterで、BottomNavigationBarを実装

Flutterで、BottomNavigationBarを実装しようとしたら、他のサイトでは最低限の情報しかなかったので、StatefulWidgetを使用した拡張を考慮したBottomNavigationBarを記事にしました。


### 各ページの用意

```dart:home.dart
import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  List<Color> colorList = [Colors.cyan, Colors.deepOrange, Colors.indigo];

  @override
  Widget build(BuildContext context) {
    return Scaffold(body: ListView.builder(
      itemBuilder: (BuildContext context, int index) {
        return Container(
          height: 80,
          color: colorList[index % colorList.length],
        );
      },
    ));
  }
}
```

```dart:settings.dart
import 'package:flutter/material.dart';

class SettingsPage extends StatefulWidget {
  const SettingsPage({Key? key}) : super(key: key);

  @override
  State<SettingsPage> createState() => _SettingsPageState();
}

class _SettingsPageState extends State<SettingsPage> {
  List<Color> colorList = [Colors.cyan, Colors.deepOrange, Colors.indigo];

  @override
  Widget build(BuildContext context) {
    return Scaffold(body: ListView.builder(
      itemBuilder: (BuildContext context, int index) {
        return Container(
          height: 80,
          color: colorList[index % colorList.length],
        );
      },
    ));
  }
}
```

### BottomNavigationBarの実装

最初のスケルトンで実装されているものをなるべく流用する形で追加します。

```dart:main.dart
import 'package:flutter/material.dart';
import 'package:myapp/ui/home.dart';
import 'package:myapp/ui/settings.dart';
import 'package:myapp/values/tab_item.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MainPage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MainPage extends StatefulWidget {
  const MainPage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  int _selectedIndex = 0;
  String _title = "";

  static const List<Widget> _pageList = <Widget>[
    HomePage(),
    SettingsPage(),
  ];

  void _onTap(int index) {
    setState(() {
      _selectedIndex = index;
      switch (index) {
        case 0:
          {
            _title = TabItem.home.name;
          }
          break;
        case 1:
          {
            _title = TabItem.settings.name;
          }
      }
    });
  }

  @override
  void initState() {
    super.initState();
    _title = widget.title;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(_title),
      ),
      body: Center(
        child: _pageList.elementAt(_selectedIndex),
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: const Icon(Icons.home),
            label: TabItem.home.name,
          ),
          BottomNavigationBarItem(
            icon: const Icon(Icons.settings),
            label: TabItem.settings.name,
          ),
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.amber[800],
        onTap: _onTap,
      ),
    );
  }
}
```

```dart:tab_item.dart
enum TabItem { home, settings }

extension TabItemExt on TabItem {
  String get name {
    switch (this) {
      case TabItem.home:
        return 'Home';
      case TabItem.settings:
        return 'Settings';
    }
  }
}
```

_onTapで、AppBarのタイトルも変更しています。