はじめに
色々なスマホアプリでページ下部にメニューがあり、タップすると画面が切り替わる機能ががあります。ボトムナビゲーションメニュー等といい、Flutterでは、BottomNavigationBar
とPageView
を使うことで簡単に実装できます。この記事では、これらを使った簡単な例をまとめます。
できるようになること
以下のGIF画像のように、アプリ下部にナビゲーションメニューがあり、タップしたり水平方向にページをスワイプすることでページを切り替えることができます。
デモのサンプルコード
上記のGIF画像のデモのサンプルコードを以下に載せます。以下のコードの元はflutter create
で作成したカウンターアプリです。BottomNavigationBar
とPageView
に関連する部分にはコメントを記載しています。
main.dartのコード
まずはじめにmain.dart
です。
main.dartimport 'package:flutter/material.dart';
import './pages/BookScreen.dart';
import './pages/CakeScreen.dart';
import './pages/CloudScreen.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'BottomNav',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
// SingleTickerProviderStateMixinを使用。後述
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
// ページ切り替え用のコントローラを定義
PageController _pageController;
// ページインデックス保存用
int _screen = 0;
// ページ下部に並べるナビゲーションメニューの一覧
List<BottomNavigationBarItem> myBottomNavBarItems() {
return [
BottomNavigationBarItem(
icon: Icon(Icons.book),
title: const Text('Book'),
),
BottomNavigationBarItem(
icon: Icon(Icons.cloud),
title: const Text('Cloud'),
),
BottomNavigationBarItem(
icon: Icon(Icons.cake),
title: const Text('Cake'),
),
];
}
@override
void initState() {
super.initState();
// コントローラ作成
_pageController = PageController(
initialPage: _screen, // 初期ページの指定。上記で_screenを1とすれば2番目のページが初期表示される。
);
}
@override
void dispose() {
// コントローラ破棄
_pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue[900],
// Appbar
appBar: AppBar(
backgroundColor: Colors.blue[900],
title: Text(
'BottomNav',
style: TextStyle(fontSize: 16),
),
),
// ),
// ページビュー
body: PageView(
controller: _pageController,
// ページ切り替え時に実行する処理
// PageViewのonPageChangedはページインデックスを受け取る
// 以下ではページインデックスをindexとする
onPageChanged: (index) {
setState(() {
// ページインデックスを更新
_screen = index;
});
},
// ページ下部のナビゲーションメニューに相当する各ページビュー。後述
children: [
BookScreen(),
CloudScreen(),
CakeScreen(),
]),
// ページ下部のナビゲーションメニュー
bottomNavigationBar: BottomNavigationBar(
// 現在のページインデックス
currentIndex: _screen,
// onTapでナビゲーションメニューがタップされた時の処理を定義
onTap: (index) {
setState(() {
// ページインデックスを更新
_screen = index;
// ページ遷移を定義。
// curveで指定できるのは以下
// https://api.flutter.dev/flutter/animation/Curves-class.html
_pageController.animateToPage(index,
duration: Duration(milliseconds: 300), curve: Curves.easeOut);
});
},
// 定義済のナビゲーションメニューのアイテムリスト
items: myBottomNavBarItems(),
),
);
}
}
SingleTickerProviderStateMixin
を使用していますが、これについては以下が大変参考になりました。
FlutterのTransition系アニメーションWidgetをすべて紹介
AnimationControllerの扱い方も手厚く解説 📝
また、ページ切替時のアニメーションの挙動については、animateToPage
のオプションで指定しています。Duration
で遷移にかける時間、curve
で挙動を指定できます。このcurve
については、以下の公式ドキュメントにどのようなものを指定できてそれぞれどのような挙動かまとまっています。
A collection of common animation curves.
ナビゲーションメニューに対応するビューのコード
あとは、アプリ下部のナビゲーションメニューに対応するページビューを3つ用意します。ここでは、適当にpages
という名前のディレクトリをlib
配下に作成し、そこにpages/BookScreen.dart
、pages/CloudScreen.dart
、pages/CakeScreen.dart
を作成しました。なお、これら3つはほぼ全て同じ内容で色やアイコンを変更しているだけです。
pages/BookScreen.dartimport 'package:flutter/material.dart';
class BookScreen extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.green[100],
// Appbar
appBar: AppBar(
backgroundColor: Colors.green[100],
title: Text(
'Book',
style: TextStyle(fontSize: 16),
),
),
body: Center(child: Icon(Icons.book)));
}
}
以下はpages/CloudScreen.dart
です。
pages/CloudScreen.dartimport 'package:flutter/material.dart';
class CloudScreen extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue[100],
// Appbar
appBar: AppBar(
backgroundColor: Colors.blue[100],
title: Text(
'Cloud',
style: TextStyle(fontSize: 16),
),
),
body: Center(child: Icon(Icons.cloud)));
}
}
以下はpages/CakeScreen.dart
です。
pages/CakeScreen.dartimport 'package:flutter/material.dart';
class CakeScreen extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.pink[100],
// Appbar
appBar: AppBar(
backgroundColor: Colors.pink[100],
title: Text(
'Cake',
style: TextStyle(fontSize: 16),
),
),
body: Center(child: Icon(Icons.cake)));
}
}
まとめ
アプリ下部に表示する基本的なナビゲーションメニューを実装しました。
SPONSORED LINK
はじめまして、山本と申します。
現在、Flutterによるアプリ開発を学習中です。
本ページのサンプルコードを応用し、
ナビゲーションメニューにボタンを4個並べてみたところ、
メニュー上のアイコン及びテキストが見えなくなりました。
正確には、アイコン及びテキストの色がメニューバーと同じとなり、
同化して見えない状態です。(アイコンのタップはできます)
初歩的な質問で大変恐縮ですが、
原因についてご教授いただけないでしょうか?
どうぞ宜しくお願いいたします。