ProviderパターンでModelを作成してheaderとfooterのあるアプリを作成します
完成形は以下のような形

(gifなのでぼやぼやですが、実際は高画質です)
footer(BottomNavigationBar
)を押した場所によって、headerの文字とbodyに表示されるものを変えています。
ファイル構造
今回はmodelを使います。
lib
├── header.dart
├── main.dart
├── models
│ └── bottom_navigation_model.dart
└── routes
├── home.dart
├── profile.dart
└── settings.dart
lib/main.dart
参考記事なんかを読んでいるとBottomNavigationBarItem
のlabel
の部分をtitle
にしてText()
で描画している記事が多いですが、それはv1.19.0からは推奨されていないようです。
@Deprecated('Use "label" instead, as it allows for an improved text-scaling experience. ' 'This feature was deprecated after v1.19.0.'), final
参考:BottomNavigationBarItem class - widgets library - Dart API
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'models/bottom_navigation_model.dart';
import 'routes/profile.dart';
import 'routes/home.dart';
import 'routes/settings.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final List _pageList = [
Profile(),
Home(),
Settings(),
];
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutterの練習', //アプリの名前
theme: ThemeData(
primaryColor: Colors.green,
),
home: ChangeNotifierProvider<BottomNavigationModel>(
create: (_) => BottomNavigationModel(),
child:
Consumer<BottomNavigationModel>(builder: (context, model, child) {
return Scaffold(
// appBar: Header(), //各ファイルでHeader()を実行するのでいらない
body: _pageList[model.currentIndex], //中身を描画
//footer部分
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'プロフィール',
),
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'ホーム',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: '設定',
),
],
currentIndex: model.currentIndex,
onTap: (index) {
model.currentIndex = index;
},
selectedItemColor: Colors.pinkAccent, //選んだ物の色
unselectedItemColor: Colors.black45, //選んでない物の色
),
);
}),
),
);
}
}
lib/header.dart
Icons.add
を記述していますが、特に意味はありません。
import 'package:flutter/material.dart';
class Header extends StatelessWidget with PreferredSizeWidget {
final String headerTitle;
Header({this.headerTitle}); //ヘッダータイトルを変更できるようにする
@override
Size get preferredSize => Size.fromHeight(kToolbarHeight);
@override
Widget build(BuildContext context) {
return AppBar(
title: Text(headerTitle),
actions: [
Padding(
padding: const EdgeInsets.all(8.0),
child: IconButton(
icon: Icon(Icons.add),
onPressed: () {
//押したときの処理
},
),
)
],
);
}
}
lib/models/bottom_navigation_model.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class BottomNavigationModel extends ChangeNotifier {
int _currentIndex = 1; //最初に表示される画面
// getterとsetterを指定しています
// setのときにnotifyListeners()を呼ぶことアイコンタップと同時に画面を更新しています。
get currentIndex => _currentIndex;
set currentIndex(int index) {
_currentIndex = index;
notifyListeners(); // View側に変更を通知
}
}
lib/routes/profile.dart
import 'package:flutter/material.dart';
import '../header.dart';
class Profile extends StatelessWidget {
final String screenName = 'プロフィール'; //headerに表示される名前
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: Header(headerTitle: screenName),
body: Center(
child: Text(screenName),
),
);
}
}
lib/routes/home.dart
import 'package:flutter/material.dart';
import '../header.dart';
class Home extends StatelessWidget {
final String screenName = 'ホーム'; //headerに表示される名前
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: Header(headerTitle: screenName),
body: Center(
child: Text(screenName),
),
);
}
}
lib/routes/settings.dart
import 'package:flutter/material.dart';
import '../header.dart';
class Settings extends StatelessWidget {
final String screenName = '設定'; //headerに表示される名前
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: Header(headerTitle: screenName),
body: Center(
child: Text(screenName),
),
);
}
}
参考
Flutter: シンプルでStatelessなBottomNavigationBarを作ってみた話
FlutterでTwitterクライアント作成②フッター追加