見出し画像

Flutter: シンプルでStatelessなBottomNavigationBarを作ってみた話

このマガジンでは、自分の学習の記録として、シンプルなサンプルを作って解説しています。同じような入門者の方の役に立てば幸いです。

達成したいこと

今回はフッターにアイコンを並べて、押すと画面遷移するやつを取りあげます。Twitter やメルカリなど様々なアプリに使われていますよね。そいつをさくっと作ってみましょう。

出来上がりイメージ

こんな感じのものが作れます。

画像1

実装の方針

1. フッターにアイコンを並べるWidgetを調べる
2. アイコンをタップしたら指定したページに切り替える

1. フッターにアイコンを並べるWidgetを調べる

これは少し調べると BottomNavigationBar() で達成できそうなことがわかりました。アイコンをタップしたときの挙動は onTap で記述できるみたいです。

2. アイコンをタップしたら指定したページに切り替える

onTap: (index) {
    // index にタップしたアイコンの番号が入っています。
    // 左から 0, 1, 2, ... と並んでいるようです。
    // indexをmodel側に渡して変更を通知。
    // 更新された番号のページを読み込めば達成できそうですね。
    model.currentIndex = index;
}

コメント部分に書いたような思考をして実装しました。
それではコード全体をみてみましょう。

まずはpageから。

// bottom_navigation_bar.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:whiskit_app/presentation/bottom_navigation/bottom_navigation_model.dart';

class BottomNavigationPage extends StatelessWidget {

 // 表示するページをリスト形式で宣言します
 List<Widget> _pageList = <Widget>[
   FirstPage(),
   SecondPage(),
 ];

 Widget build(BuildContext context) {
   return MaterialApp(
     // テーマはなんでも大丈夫です
     theme: ThemeData(
       brightness: Brightness.dark,
       primaryColor: Colors.lightBlue[800],
       accentColor: Colors.cyan[600],
       textTheme: TextTheme(),
     ),
     home: ChangeNotifierProvider<BottomNavigationModel>(
       create: (_) => BottomNavigationModel(),
       child:
           Consumer<BottomNavigationModel>(builder: (context, model, child) {
         return Scaffold(
           // 今選択している番号のページを呼び出します。
           body: _pageList[model.currentIndex], 
           bottomNavigationBar: BottomNavigationBar(
             // 選択時の色やBarの色など設定できます。
             backgroundColor: Colors.black54,
             // 選択中のアイコンを更新しています。
             currentIndex: model.currentIndex,

             // ここからが肝です。
             onTap: (index) {
               // indexで今タップしたアイコンの番号にアクセスできます。
               model.currentIndex =
                   index; // indexをモデルに渡したときに notifyListeners(); を呼んでいます。
             },
             items: [
               // フッターアイコンの要素を並べています 最低2個以上必要みたいです。
               BottomNavigationBarItem(
                 // アイコンとラベルは自由にカスタムしてください。
                 icon: Icon(Icons.face), 
                 label: '',
               ),
               BottomNavigationBarItem(
                 icon: Icon(Icons.fastfood),
                 label: '',
               ),
             ],
           ),
         );
       }),
     ),
   );
 }
}

// シンプルな画面構成のページを2つ用意しておきます。
// 本番では他のファイルで作り込んだページを指定して使っていくことになると思います。
class FirstPage extends StatelessWidget {
 Widget build(BuildContext context) {
   return Scaffold(
     body: Center(
         child: Icon(
       Icons.face,
       size: 200,
     )),
   );
 }
}

class SecondPage extends StatelessWidget {
 Widget build(BuildContext context) {
   return Scaffold(
     body: Center(
         child: Icon(
       Icons.fastfood,
       size: 200,
     )),
   );
 }
}

こちらはProviderです。

// bottom_navigation_model.dart

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

class BottomNavigationModel extends ChangeNotifier {

 int _currentIndex = 0;
 
 // getterとsetterを指定しています
 // setのときにnotifyListeners()を呼ぶことアイコンタップと同時に画面を更新しています。
 get currentIndex => _currentIndex;
 
 set currentIndex(int index) {
   _currentIndex = index;
   notifyListeners(); // View側に変更を通知
 }
 
}

今回は以上になります!

Statefulwidgetを使ったサンプルが多かったので、StatelessWidgetだけで構成してみました。 参考になれば幸いです!

最後まで読んでもらえて嬉しいです。よければフォローもお待ちしています。サポートは記事を書くときのコーヒーになります。