FlutterでBottomNavigationBar + Pagerを実装する手法について
はじめに
今回は、FlutterでのBottomNavigationBarの実装とBottomNavigationBar + Pagerの実装について学んだことをメモとして残しておこうと思います。
この記事に書いてあること
BottomNavigationBarの実装
BottomNavigationBarの中にPagerを入れる実装
対象とする読者
FlutterでBottomNavigationBarの実装を知りたい方
FlutterでBottomNavigationBarにPagerを入れる実装をやりたい方
Flutterをはじめたばかりの方
自分もはじめたばかりですが、誰かの助けになれば幸いです。
それではやっていきましょう。
BottomNavigationBarの実装
今回紹介するサンプルのイメージは、次のとおりです。
まずはじめに、BottomNavigationBarについてマテリアルデザインのガイドラインをみていきましょう。
先のリンク先を見ると、Bottom navigationの使用にはいくつか制約があります。
- 単一のタスクには使用しない(設定など)
- 3 ~ 5この要素を持つ(3つより少なかったり、5つより要素が多い場合は使用しない)
- iOSとAndroidで若干挙動が異なる
- アイコン下部のTextを長くしたり、折り返したりしない etc..
これらを押さえた上で、実際に作成していきましょう。
main.dartの中で、Navigatorを利用したいので、MaterialAppクラスをmainの中で指定します。
void main() {
runApp(new MaterialApp(
title: "BottomNavigationSample",
home: new Home(),
));
}
MaterialAppクラスでは、 home、routes、onGenerateRoute、builderのいずれかのうち一つをnull以外に指定する必要があります。
今回は、homeを可変な状態を管理するWidgetのStatefulWidgetを指定します。
今回指定しているHomeクラスは、次のように定義します。
class Home extends StatefulWidget {
State<StatefulWidget> createState() {
return new HomeState();
}
}
createStateでWidgetが開いている間の状態を管理するStateをインスタンス化します。
次にStateクラスを継承した、HomeStateを次のように新しく作成します。
class HomeState extends State<Home> {
int currentIndex = 0;
final List<Widget> tabs = [
SampleTabItem("左の画面", Colors.red),
SampleTabItem("真ん中の画面", Colors.green),
SampleTabItem("右の画面", Colors.cyan),
];
void onTabTapped(int index) {
setState(() {
currentIndex = index;
});
}
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("BottomNavigationSample"),
backgroundColor: Colors.blue,
),
body: tabs[currentIndex],
bottomNavigationBar: BottomNavigationBar(
onTap: onTabTapped,
currentIndex: currentIndex,
items: [
BottomNavigationBarItem(
icon: new Icon(Icons.home),
title: new Text('Home'),
),
BottomNavigationBarItem(
icon: new Icon(Icons.mail),
title: new Text('Messages'),
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
title: Text('Profile')
)
],
),
);
}
}
ここで、実装する際に抑える点は3つです。
- Tab選択時の中身をListでもつ
- Tabをタップした際の挙動をかく
- 全体のレイアウトを組む
まずは、Tab選択時の中身のListについてです。
Tab選択時の中身のListでもつ
先のHomeStateにて、tabsと定義しているWidgetのリストは、下部のタブをタップした際に、各Tabの選択したものに関連するWidgetを表示した際の中身になります。
今回、自分の場合は、タイトルの文字列とカラーを指定するSampleTabItemを定義しています。
SampleTabItemの実装は次のようになります。
class SampleTabItem extends StatelessWidget {
final String title;
final Color color;
const SampleTabItem(this.title, this.color) : super();
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: this.color,
body: new Container(
child: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(this.title,
style: new TextStyle(
color: Colors.white,
fontSize: 36.0,
fontWeight: FontWeight.bold))
],
),
),
),
);
}
}
タイトルとカラーを渡すためにコンストラクタを次のように定義しています。
const SampleTabItem(this.title, this.color) : super();
Widget buildの中では、渡されたタイトルとカラーを指定して表示するようにレイアウトを組みます。
これをHomeStateの中でリストとしてTabの中身を持ちます。
Tabをタップした際の挙動をかく
タップした際の挙動についての関数onTabTappedを定義します。
bottom_navigation_bar.dartの中身を読むと、setStateにタブをタップした際のindexが渡ってくるので、HomeStateのなかに定義した現在のindexをもつcurrentindexに代入して選択したTabのindexを取得します。
void onTabTapped(int index) {
setState(() {
currentIndex = index;
});
}
全体のレイアウトを組む
HomeStateのWidgetのbuildの中で全体のレイアウトを組みます。
骨組みを作ったら、bodyにはWidgetのリストを指定します。
ScaffoldにbottomNavigationBarを指定できるので、こちらで組みたいレイアウトを指定していきます。
BottomNavigationBarクラスでは、onTapには先ほど作成したonTabTappedを指定して、currentIndexもonTabTappedで代入したcurrentIndexを指定します。
itemsにはTabに表示したいItemをBottomNavigationBarItemで指定します。
BottomNavigationBarItem(
icon: Icon(Icons.person),
title: Text('Profile')
)
BottomNavigationBarItemにはiconとtitleを入れることができるので、これらを指定して入れます。
ここまでできれば、BottomNavigationBarの実装が完了です。
BottomNavigationBarの中にPagerを入れる実装
BottomNavigationBarを実装した上で、選択したタブの中にさらにPagerを入れたいことが出てくると思います。
そういう時の実装について、こちらで解説していきます。
まずはじめに、Pagerの実装についてやっていきましょう。
Pagerについて、今回はTabPagerItemと定義して自分は実装しました。
class TabPagerItem extends StatefulWidget {
State<StatefulWidget> createState() {
return TabPagerState();
}
}
例によって、StatfulWidgetを継承したクラスを作成し、状態を保つクラスを作成します。自分はTabPagerStateを状態をもつクラスを作成しました。
TabPagerStateを次のように作成します。
class TabPagerState extends State<TabPagerItem> with SingleTickerProviderStateMixin {
TabController controller;
void initState() {
super.initState();
controller = new TabController(length: 3, vsync: this);
}
void dispose() {
super.dispose();
controller.dispose();
}
Widget build(BuildContext context) {
return new Scaffold(
body: new TabBarView(
children: <Widget>[
new SampleTabItem("1個目", Colors.amber),
new SampleTabItem("2個目", Colors.deepPurpleAccent),
new SampleTabItem("3個目", Colors.orange),
],
controller: controller,
),
);
}
}
pagerを作成するのに、TabBarViewを用いるので、TabBarもしくはTabBarViewを管理するTabControllerを作成します。
コールバックを利用するのに、withでSingleTickerProviderStateMixinを指定します。
initStateでControllerをインスタンス化して、Pagerのアイテム数をlengthで指定します。
今回はPagerの中身を3つにするため、3を指定しています。
disposeでControllerのdisposeを呼んで、解除することを忘れないでください。
Widget buildではPagerに表示したいレイアウトを使用します。
TabBarViewの中で、表示したいWidgetとcontrollerを指定します。
次に、このPagerをBottomNavigationBarの選択のWidgetのなかに入れます。
class HomeState extends State<Home> {
...
final List<Widget> tabs = [
TabPagerItem(),
SampleTabItem("真ん中の画面", Colors.green),
SampleTabItem("右の画面", Colors.cyan),
];
...
}
先に作成していた、tabsにPagerそのものを指定します。
ここまでできれば、冒頭のgifのサンプルの作成ができます。
おわりに
今回は、FlutterでBottomNavigationBarとBottomNavigationBar + Pagerを実装するための解説を自分なりにやってみました。
拙いところがあってわかりづらかったりしたら申し訳ないです。
間違っている部分があったり、説明がよくわからない部分などあれば、コメントをしていただけると嬉しいです。
また、今回のサンプルコードは次のリンクから入手できます。
クローンしてビルドすれば試すことができるのでやってみてください。
最後まで見ていただきありがとうございました。それではまたの機会に。
参考リンク
今回実装するにあたって、公式のサンプルと次のサンプルを参考にさせていただきました。
ぜひ、スターをしてこちらも試してみてください。