タブ切り替えをStateful Widgetで実装する方法を紹介します。
Stateful Widgetの場合はDefaultTabController
を使わなくてもタブ切り替えを実装することが可能です。DefaultTabController
を使ったケースはこちらをご覧ください。
まずはサンプルコードの全体をご覧ください。
import 'package:flutter/material.dart';void main() { runApp(const MyApp());}class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'タブバーを試す', theme: ThemeData( primarySwatch: Colors.blue, ), home: const TabBarScreen(), ); }}class TabBarScreen extends StatefulWidget { const TabBarScreen({Key? key}) : super(key: key); @override _TabBarScreenState createState() => _TabBarScreenState();}class _TabBarScreenState extends State<TabBarScreen> with TickerProviderStateMixin { late TabController _tabController; @override void initState() { super.initState(); _tabController = TabController(length: 3, vsync: this); } @override void dispose() { _tabController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('タブバーのサンプル'), bottom: TabBar( controller: _tabController, tabs: const [ Tab( icon: Icon(Icons.home), text: 'ホーム', ), Tab( icon: Icon(Icons.access_time_sharp), text: '通知', ), Tab( icon: Icon(Icons.build), text: '設定', ), ], onTap: (index) { print('$index番目の画面になりました'); }, ), ), body: TabBarView( controller: _tabController, children: const [ Center( child: Text( 'ホーム画面', style: TextStyle(fontSize: 40.0), ), ), Center( child: Text( '通知画面', style: TextStyle(fontSize: 40.0), ), ), Center( child: Text( '設定画面', style: TextStyle(fontSize: 40.0), ), ), ], ), ); }}
ひとつひとつポイントを見ていきましょう。
以下の30行目からはじまる_TabBarScreenState
のコードを見てください。
class _TabBarScreenState extends State<TabBarScreen> with TickerProviderStateMixin { late TabController _tabController; @override void initState() { super.initState(); _tabController = TabController(length: 3, vsync: this); }
32行目のところでTabConrtoller
の変数を保持しています。
この_tabController
がタブの切り替えを制御するクラスです。
Stateless Widgetのケースで使用していたDefaultController
の代わりに必要になります。
37行目のようにinitState
の中でTabController
の実体を作成しています。
このとき、length:
で必要なタブの数を指定します。
この37行目のコードを書くのに必要なのが、31行目で指定しているTickerProviderStateMixin
です。
タブの切り替え時にアニメーションの演出が入りますが、そのために必要なパラメーターです。TabController
は内部でAnimationController
を使用していて、vsync:
にアニメーションを動作させるクラスのインスタンスを指定してあげます。この場合はthis
= _TabBarScreenState
ですね。
あとは、タブの具体的な準備です。
以下のコードを見てください。
appBar: AppBar( title: const Text('タブバーのサンプル'), bottom: TabBar( controller: _tabController, tabs: const [ Tab( icon: Icon(Icons.home), text: 'ホーム', ), Tab( icon: Icon(Icons.access_time_sharp), text: '通知', ), Tab( icon: Icon(Icons.build), text: '設定', ), ], onTap: (index) { print('$index番目の画面になりました'); }, ), ),
AppBar
のbottom:
の部分にタブバーの具体的な設定を書いていきます。
52行目で_tabController
を指定することで、DefaultTabController
を使わずにタブ切り替えを実現できます。
また、67行目のようにonTap:
でタブを切り替えたときのイベントを受け取ることが可能です。index
には切り替え後のタブ番号が設定されてきます。
タブごとの内容表示も必要です。
以下のコードを見てください。
body: TabBarView( controller: _tabController, children: const [ Center( child: Text( 'ホーム画面', style: TextStyle(fontSize: 40.0), ), ), Center( child: Text( '通知画面', style: TextStyle(fontSize: 40.0), ), ), Center( child: Text( '設定画面', style: TextStyle(fontSize: 40.0), ), ), ], ),
ここでも73行目で_tabController
を指定しています。children:
にはタブごとの表示内容を設定します。
今回はサンプルなので、Center
とText
のシンプルな内容ですが、
実際にはかなり複雑化すると思います。
タブごとに別のWidgetとして切り出して読み込む形にするのが現実的です。DefaultTabController
を使うパターンよりもコードのネストが1階層減るため見やすくなるのも利点だと思います。
Flutterのコードはただでさえネストが激しくなりがちなので・・