BLoCでTabViewを作成する方法
FlutterでTabViewを作るときはDefaultTabControllerを使うことが多いですが、BLoCを使うこともできます。
flutter_bloc
を用いる場合、以下のように作ります。
- Tab情報をenum等のStateとしてして持つ。
- Tabが選択された際にEventをBLoCに送る。EventはTab情報(State)をプロパティとして持つ。
- Eventを受け取ったBlocが選択されたTabをStateとして通知する。
- View側がStateを受け取り、選ばれたTabの内容を描画する。
実際のコード
flutter_bloc
を使って以下のようなコードを作成します。
BLoC
// Bloc
// BlocState
enum AppTab { a, b }
// BlocEvent
abstract class TabEvent extends Equatable {
const TabEvent();
}
class UpdateTab extends TabEvent {
final AppTab tab;
const UpdateTab(this.tab);
@override
List<Object> get props => [tab];
@override
String toString() => 'UpdateTab { tab: $tab }';
}
// Bloc
class TabBloc extends Bloc<TabEvent, AppTab> {
TabBloc() : super(AppTab.a);
@override
Stream<AppTab> mapEventToState(TabEvent event) async* {
if (event is UpdateTab) {
yield event.tab;
}
}
}
View
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider<TabBloc>(
create: (context) => TabBloc(),
child: TabBlocPage(),
),
);
}
}
class TabBlocPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<TabBloc, AppTab>(
builder: (context, activeTab) {
return Scaffold(
appBar: AppBar(
title: const Text('TabBlocExample'),
),
// 選ばれたTab(State)によって描画する
body: activeTab == AppTab.a ? TabA() : TabB(),
bottomNavigationBar: TabSelector(
activeTab: activeTab,
// ユーザーが選んだTabをEventに持たせて送るFunctionをTabSelectorのメソッドに割り当てる
onTabSelected: (tab) => BlocProvider.of<TabBloc>(context).add(UpdateTab(tab)),
),
);
},
);
}
}
// TabView
class TabA extends StatelessWidget {
const TabA({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: Center(child: Text('TabA')),
);
}
}
class TabB extends StatelessWidget {
const TabB({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: Center(child: Text('TabB')),
);
}
}
// BottomNavigationBar
class TabSelector extends StatelessWidget {
const TabSelector({
Key key,
this.activeTab,
this.onTabSelected,
}) : super(key: key);
final AppTab activeTab;
final Function(AppTab) onTabSelected;
@override
Widget build(BuildContext context) {
return BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.circle),
label: 'TabA',
),
BottomNavigationBarItem(
icon: Icon(Icons.crop_square),
label: 'TabB',
),
],
currentIndex: AppTab.values.indexOf(activeTab),
selectedItemColor: Colors.amber[800],
// ユーザーがTabを選択した際にBLoCにEventを送る
onTap: (index) => onTabSelected(AppTab.values[index]),
);
}
}