【BottomNavigationBar】フッターで画面切り替えする方法を徹底解説【Flutter】

こんにちはyu_to(@yu_to_python)です。

今回はFlutterでフッターを使った画面切り替えの実装方法と、そのフッターを作る際に使用されるBottomNavigationBarというWidgetについて解説していきます。

そもそもWidgetの事について詳しく知らないという方はこちらの記事で詳しく解説しているので参考にしてください。

【Flutter】UI構築する際の基本Widgetついて解説!【サンプルコードあり】

この記事を最後まで読めば画面切り替えの実装方法とBottomNavigationBarの使い方、よく使うプロパティについて理解できると思うので是非最後まで読んでみてください。

フッターとは

BottomNavigationBarの解説に行く前にそもそもアプリにおけるフッターとはどの様な役割を担っているかの簡単に説明します。

フッターとは、アプリ最下部のスペースの事を指します。

多くのアプリの最下部にアイコンが3~5つくらい並んでるあれですね。

近年のスマートフォンは年々画面サイズが大きく作られる傾向があり、多くの人が画面の上まで指が届きづらく両手でアプリを操作しがちです。

なので近年のアプリでは画面上部に配置するボタン等の要素は少なく、画面下部に配置する要素は多めなっているパターンが多いです。

それに応じてUIにおけるフッターの重要度も高く、適切なフッターを設ける事によって片手のみでアプリ内を素早く移動できるようになりUX(ユーザー体験)の向上に繋がります。

ただ基本フッターに載せられるメニュー数は3~5個までが一般的で限りがあるので、特にユーザーに使って欲しい機能を厳選して効率よく配置する必要があります。

例としてメルカリのアプリで実装されているフッターのメニューが下記です。

  1. アプリのホーム画面に戻れる「ホーム」
  2. 通知を閲覧できる「お知らせ」
  3. 商品を出品できる「出品」
  4. メルペイ等にすぐアクセスできる「支払い」
  5. 自分のアカウント情報を参照できる「マイページ」
メルカリのフッター

まさにメルカリの持つ機能を網羅できた模範的なフッターだと思います。

こんな感じでメニューには文字ではなくアイコンも表示させる事がスタンダードで、機能に対する直感的なアイコン選びのセンスも問われるので思ったより設計が難しいのがこのフッターという要素なのです。

BottomNavigationBarの特徴

簡単にフッターを作成できる

BottomNavigationBarを使うことで簡単にフッター機能を作成することができます。

UI構築のスタート地点になるWidgetであるScaffoldにもデフォルトでその名の通りの「bottomNavigationBar」というプロパティが用意されており、そこに指定するだけで作成できてしまいます。

Scaffoldについてはこちらで解説しているので良ければ参考にしてみてください。

【Flutter】UI構築のスタート地点Scaffoldを徹底解説【サンプルコードあり】

サンプルコード

コピペですぐ動かせるのでまずは実際に動かしてみてください。

動作確認したバージョンは下記の通りです。

・Flutter 3.0.1

・Dart 2.13.3

main.dart
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'demo',
      home: Home(),
    );
  }
}

class Home extends StatefulWidget {
  const Home({Key key}) : super(key: key);
  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  // 選択中フッターメニューのインデックスを一時保存する用変数
  int selectedIndex = 0;

  // 切り替える画面のリスト
  List<Widget> display = [HomePage(), Notice(), MyPage()];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text('BottomNavigationBar')),
        body: display[selectedIndex],
        bottomNavigationBar: BottomNavigationBar(
          items: [
            BottomNavigationBarItem(icon: Icon(Icons.home), label: 'ホーム'),
            BottomNavigationBarItem(
                icon: Icon(Icons.notifications_none), label: 'お知らせ'),
            BottomNavigationBarItem(icon: Icon(Icons.people), label: 'マイページ'),
          ],
          // 現在選択されているフッターメニューのインデックス
          currentIndex: selectedIndex,
          // フッター領域の影
          elevation: 0,
          // フッターメニュータップ時の処理
          onTap: (int index) {
            selectedIndex = index;
            setState(() {});
          },
          // 選択中フッターメニューの色
          fixedColor: Colors.red,
        ));
  }
}

// --------- 切り替える画面 -----------
class HomePage extends StatelessWidget {
  const HomePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(child: Text('ホーム'));
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(child: Text('お知らせ')),
      color: Colors.red[200],
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(child: Text('マイページ')),
      color: Colors.green[200],
    );
  }
}

動きはこんな感じでフッターメニューを選択するとそれに応じた画面がメイン画面で切り替わっているのが分かると思います。

よく使うプロパティ

items(必須)

BottomNavigationBarに表示させる要素をリストで設定するプロパティです。

ここには基本的には「BottomNavigationBarItem」という専用のWidgetが指定されます。

(下のtips欄で紹介してます)

フッターに表示させるアイコンとテキストはこのBottomNavigationBarItemの方で個別に設定することになります。

一応他のWidgetも指定可能です。

itemsプロパティ
...
bottomNavigationBar: BottomNavigationBar(
  items: [
    BottomNavigationBarItem(icon: Icon(Icons.home), label: 'ホーム'),
    BottomNavigationBarItem(
        icon: Icon(Icons.notifications_none), label: 'お知らせ'),
    BottomNavigationBarItem(icon: Icon(Icons.people), label: 'マイページ'),
  ],
...

currentIndex

現在選択されているフッターメニューのインデックスを指定するプロパティです。

このcurrentIndexに指定したインデックスを切り替える事でメイン画面に表示させるWidgetを切り替えることができます。

インデックスは、下で紹介するonTapプロパティで操作します。

一応必須のプロパティではないですが、設定しないとアイコンタップしても画面は切り替わっているのにアイコンの色は前のアイコンについたままの状態になってしまって不自然なので実質必須になってます。

currentIndexプロパティ
...
// 現在選択されているフッターメニューのインデックス
currentIndex: selectedIndex,
...

onTap

フッターメニュータップ時の処理を指定するプロパティです。

先程紹介したcurrentIndexのインデックスを切り替えたり、画面再描画の処理を記載したりします。

記述の方法は以下の3通りあるので場合に応じて使い分けましょう。

処理の指定方法
▼アロー関数 ーーーーーーーーーーーーーーーーーーーーーーーーー
onTap: () => {
  print('アイコンが押された!'),
  print('アイコンが押された!'),
},

or

※処理が一行の場合ブラケットは省略可能
onTap: () => print('アイコンが押された!'),

▼ブラケット内で処理を書く ーーーーーーーーーーーーーーーーーーー
onTap: () {
  print('アイコンが押された!');
},

▼voidFunctionを直接指定する ーーーーーーーーーーーーーーーーー
~~~
void voidFunction() {
  print('アイコンが押された!');
}
~~~
onTap: voidFunction,
onTapプロパティ
...
// フッターメニュータップ時の処理
onTap: (int index) {
  selectedIndex = index;
  setState(() {});
},
...

fixedColor

選択中フッターメニューの色を指定するプロパティです。

指定しなければデフォルトで青色になります。

UIのテーマ色に応じてここの色も変えてあげると統一感が出ていい感じになります。

fixedColorプロパティ
...
// 選択中フッターメニューの色
fixedColor: Colors.red,
...

elevation

フッターに影を付けるプロパティです。

デフォルトは4に設定されています。

0にすると影が消えて、数字を大きくすれば影が濃くなっていきます。

elevationプロパティ
...
// フッター領域の影
elevation: 0,
...

tips

BottomNavigationBarItem

BottomNavigationBarで個別のフッター要素を作る際に使われるWidgetです。

ほぼBottomNavigationBarのitemsプロパティ内でしか使われないと思って貰っていいかと思います。

必須プロパティとして下記があります。

  1. icon:フッター要素のアイコンを指定
  2. label:アイコンの下に表示させるテキストを指定
<meta charset=”utf-8″>BottomNavigationBarItem
...
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'ホーム'),
...

その他の仕様、プロパティについては公式ドキュメントに記載があるので参考にしてみてください。

おわり

今回はBottomNavigationBarについて解説してきました。

今回紹介した仕様やプロパティ以外も、もっと深堀りしたい方は公式ドキュメントを参照してみてください。

このブログでは他にもFlutterに関する記事を上げているので良ければそちらも参考にしてみてください。

質問やご指摘もお待ちしてますー。

【2022年最新】現役エンジニアがFlutter初学者向けおすすめ技術書3選を紹介!

 

【Flutter】AppBarでアプリのヘッダーを作る方法を徹底解説!【サンプルコードあり】

【Flutter】ElevatedButtonでイケてるボタンのレイアウトを簡単作成【サンプルコードあり】