タブ内のページ遷移するボタン
Flutterで、タブ内のボタンを押したら、新しいページ遷移される仕組みを作ってみましょう。デモページは以下をご覧ください、(上タブと下タブでは、コードの構成が少し異なります。)
↑下タブ版の例上タブ… DefaultTabController(上部に設置するタブ)
下タブ… BottomNavigationBar(下部に設置するタブ)
1. まずはタブとそのページを作ってみる
上タブはflutter.dev/docsを、
下タブは、flutter.dev/flutter/materialを
参考に、タブとそのページのみを作成してみましょう。
2. ページ遷移を作成する
以下のURL
flutter.dev/docs を参考に、ページ遷移を作成する
3. そのまま実装すると、エラーが発生する!
上タブ版のエラー
Navigator operation requested with a context that does not include a Navigator.
このエラーメッセージは、「Navigator.pushで、Navigatorが見つからない」といっています。NavigatorオブジェクトはMaterialApp内で生成されますが、そのままのコードだと、MaterialAppのContextへ辿ることができません。
参考:Flutterの公式YouTube
下タブ版のエラー
Error: Getter not found: 'context'.
このエラーメッセージは、「ページ1の画面にはcontextがない」といっています。
解決法
上タブ版の解決策(どちらでもOK)
- DefaultTabControllerをBuilderで囲む
または - DefaultTabController全体を別Widgetに切り出す
(今回は、2個目の切り出す方法を採用)
下タブ版の解決策
- ページ1、ページ2それぞれを別Widgetを別クラスに切り出す
まとめ
上タブ版
import 'package:flutter/material.dart';
// 最初に呼び出される関数(MyApp関数)
void main() {
runApp(TabBarDemo());
}
// 全体
class TabBarDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: TabPage(),
);
}
}
// 2つのタブの画面
class TabPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
// Scaffold を使うことで、 appBar を利用できる
child: Scaffold(
appBar: AppBar(
// appBar の bottomの部分 に作成
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.home)),
Tab(icon: Icon(Icons.directions_walk)),
],
),
title: Text('Demo (top)'),
),
body: TabBarView(
children: [
// ページ1
Center(
child: RaisedButton(
child: Text('ページ3へ'),
color: Colors.orange,
textColor: Colors.white,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Page3(),
),
);
},
),
),
// ページ2
Center(
child: Text('ページ2'),
),
],
),
),
);
}
}
// ページ3(遷移するページ)
class Page3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("ページ3"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('戻る'),
),
),
);
}
}
下タブ版
import 'package:flutter/material.dart';
// 最初にMyAppを実行する
void main() => runApp(MyApp());
// 初期設定
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: MyStatefulWidget(),
theme: ThemeData(
primarySwatch: Colors.blue,
),
);
}
}
// 状態管理
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
@override
// 更新
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
// 初期状態での選択は左のタブ
int _selectedIndex = 0;
static List<Widget> _widgetOptions = <Widget>[
// ページ1の画面
Page1(),
// ページ2の画面
Page2(),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('DEMO (bottom)'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
// 下のナビゲーションボタン
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('ページ1'),
),
BottomNavigationBarItem(
icon: Icon(Icons.directions_walk),
title: Text('ページ2'),
),
],
// 選択をナビゲーションアイコンに反映
currentIndex: _selectedIndex,
// 選択したときはオレンジ色にする
selectedItemColor: Colors.amber[800],
// タップできるように
onTap: _onItemTapped,
),
);
}
}
// (ページ1)左ページ
class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: Text('ページ3へ'),
color: Colors.orange,
textColor: Colors.white,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NewPage(),
),
);
},
),
);
}
}
// (ページ2)右ページ
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text(
'ページ2',
);
}
}
// ページ3(遷移するページ)
class NewPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("ページ3"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('戻る'),
),
),
);
}
}
これでページ遷移の仕組みが完成しました!
最後に
Flutterの初学者の方々のお役に立てれば幸いです。もし誤り等ございましたら、コメントいただければと思います。