目次
概要
画面下にボタンを羅列して画面を切り替える方法がある。その方法が今回の記事。
まず、TabBarを表示するベースとなる画面を作る。
その画面とは別に、その表示する画面のファイルを作成して、ベースとなる画面で表示するという本心だ。
ファイルの数が多いが、「表示する画面」の4つファイルは同じような構成のため、数に圧倒されないで欲しい。
そして、今回は画像を表示しているが、画像でなくてもTextを表示するだけでも何も問題ない。
ソースコード
アプリ実行部分
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:concentration/TabBar/MainTabBarView.dart';
void main() async{
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),
useMaterial3: true,
),
home: MainTabBarView(),
);
}
}
画面全体
import 'package:concentration/TabBar/Screens/FourthView.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'MainTabBarViewModel.dart';
import 'Screens/FirstView.dart';
import 'Screens/SecondView.dart';
import 'Screens/ThirdView.dart';
class MainTabBarView extends ConsumerWidget {
MainTabBarView({Key? key}) : super(key: key);
MainTabBarViewModel _viewModel = MainTabBarViewModel();
List<Widget> display = [
const FirstView(),
const SecondView(),
const ThirdView(),
const FourthView()
];
@override
Widget build(BuildContext context, WidgetRef ref) {
_viewModel = ref.watch(mainTabModelProvider);
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(_viewModel.title),
),
body: display[_viewModel.currentIndex],
bottomNavigationBar: BottomNavigationBar(
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'First'),
BottomNavigationBarItem(icon: Icon(Icons.chat), label: 'Second'),
BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Third'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Fourth'),
],
currentIndex: _viewModel.currentIndex,
onTap: (int index) {
_viewModel.selectedTab(index);
},
selectedItemColor: Colors.white,
unselectedItemColor: Colors.white54,
backgroundColor: Colors.blue,
type: BottomNavigationBarType.fixed,
),
);
}
}
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'MainTabBarRepository.dart';
final mainTabModelProvider = ChangeNotifierProvider((ref) => MainTabBarViewModel(repository: ref.read(MainTabBarRepositoryProvider)));
class MainTabBarViewModel extends ChangeNotifier {
MainTabBarRepository? repository;
int currentIndex = 0;
String title = "First";
MainTabBarViewModel({this.repository});
void selectedTab(int index) {
currentIndex = index;
switch (currentIndex) {
case 0:
title = "First";
case 1:
title = "Second";
case 2:
title = "Third";
case 3:
title = "Fourth";
}
notifyListeners();
}
}
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'MainTabBarModel.dart';
final MainTabBarRepositoryProvider = Provider((ref) => MainTabBarRepositoryImpl(model: ref.read(mainTabBarModelProvider)));
abstract class MainTabBarRepository {
}
class MainTabBarRepositoryImpl implements MainTabBarRepository {
MainTabBarRepositoryImpl({required MainTabBarModel model}): _model = model;
final MainTabBarModel _model;
}
import 'package:flutter_riverpod/flutter_riverpod.dart';
final mainTabBarModelProvider = Provider((ref) => MainTabBarModel());
class MainTabBarModel {
}
表示する画面
libと同じ階層にあるimagesディレクトリに画像を以下の名前の画像を追加しておく。
- 01_img.PNG
- 02_img.PNG
- 03_img.PNG
- 04_img.PNG
画像の追加方法はこちら。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class FirstView extends ConsumerWidget {
const FirstView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
body: Container(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 200,
height: 200,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/01_img.PNG'),
fit: BoxFit.contain,
)
)
),
],
),
)
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class SecondView extends ConsumerWidget {
const SecondView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
body: Container(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 200,
height: 200,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/02_img.PNG'),
fit: BoxFit.contain,
)
)
),
],
),
)
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class ThirdView extends ConsumerWidget {
const ThirdView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
body: Container(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 200,
height: 200,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/03_img.PNG'),
fit: BoxFit.contain,
)
)
),
],
),
)
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class FourthView extends ConsumerWidget {
const FourthView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
body: Container(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 200,
height: 200,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/04_img.PNG'),
fit: BoxFit.contain,
)
)
),
],
),
)
);
}
}
デモ動画
詳細
今回の主役はこちらだ。
List<Widget> display = [
const FirstView(),
const SecondView(),
const ThirdView(),
const FourthView()
];
bottomNavigationBar: BottomNavigationBar(
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'First'),
BottomNavigationBarItem(icon: Icon(Icons.chat), label: 'Second'),
BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Third'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Fourth'),
],
currentIndex: _viewModel.currentIndex,
onTap: (int index) {
_viewModel.selectedTab(index);
},
selectedItemColor: Colors.white,
unselectedItemColor: Colors.white54,
backgroundColor: Colors.blue,
type: BottomNavigationBarType.fixed,
),
引数名 | 設定内容 |
bottomNavigationBar | BottomNavigationBarオブジェクトを設定する |
items | BottomNavigationBarItemをメニューの数だけ格納する |
currentIndex | 在の表示している画面の番号を設定する。(displayの添字) |
selectedItemColor | 選択されている時のボタンの色を設定する |
unselectedItemColor | 選択されていない時のボタンの色を設定する |
backgroundColor | タブバーの背景色を設定する |
type | BottomNavigationBarTypeアイコンの表示方法を設定する |
まず、こうすることで画面の下にタブバーを表示することができる。
では、今度は更新処理だ。今回はアーキテクチャのことも考えて、 Repositoryクラスなどを作成している。
まず、タブバーのボタンを押下すると以下の処理が行われる。
onTap: (int index) {
_viewModel.selectedTab(index);
},
そして、viewModelのselectedTabの処理が行われる。
void selectedTab(int index) {
currentIndex = index;
switch (currentIndex) {
case 0:
title = "First";
case 1:
title = "Second";
case 2:
title = "Third";
case 3:
title = "Fourth";
}
notifyListeners();
}
こうすることで、以下で表示しているタイトルと表示するビューを変更している。
List<Widget> display = [
const FirstView(),
const SecondView(),
const ThirdView(),
const FourthView()
];
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(_viewModel.title),
),
body: display[_viewModel.currentIndex],
ただ、変数を更新しただけでは画面は更新されない。そのためにも以下のメソッドをタップした時に行われるviewModelクラスのメソッド内で呼び出す必要がある。
notifyListeners();