質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

Q&A

解決済

1回答

4103閲覧

Flutterでナビゲーションタブ機能のウィジェットを2つ表示したい

Yariii

総合スコア61

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

0グッド

0クリップ

投稿2020/09/09 11:28

こんにちは。

今回、添付画像のようなタブ切り替えを実装したいです。
イメージ説明

appBar:
body:
bottomNavigationBar:
の3つのウィジェット構成で、appBarとbodyだけ、bottomNavigationBarのタブで切り替える仕様です。
「呼ぶ」と「探す」の2つのタブがあり、それぞれappBarとbodyの内容が違うので、別個に切り替えるイメージです。

それは実装できたのですが、
その上で、「探す」の画面だけさらに「TabBar」があり、そのタブでコンテンツを切り替えたいのです、しかしやり方がわからず困っています。
コードを見ていただくとおり、今回appBarとbodyをそれぞれクラスを別個に分けているためか、appBarにTabBarを追加すると「Undefined name」エラーを吐いてしまいます。

以下コードです。

▼ホーム画面(ここで内容を切り替える、デフォは「呼ぶ」画面)

//ホーム画面 class SignedInTop extends StatefulWidget { @override _SignedInTopState createState() => _SignedInTopState(); } class _SignedInTopState extends State<SignedInTop> { bool _alreadyDisposed = false; int _selectedIndex = 0; //下ナビでアプリバーの切り替え static List<dynamic> _userHomeAppBar = <dynamic>[ GuestCallAppBar(), GuestSearchAppBar(), ]; //下ナビでボディの切り替え static List<Widget> _userHomeBody = <Widget>[ Container( child: CallCast(), ), Container( child: SearchCast(), ), ]; void _onItemTapped(int index) { setState(() { _selectedIndex = index; }); } @override void initState() { super.initState(); } @override void didChangeDependencies() { super.didChangeDependencies(); } @override void setState(Function fn) { if (_alreadyDisposed) return; super.setState(fn); } @override void dispose() { _alreadyDisposed = true; super.dispose(); } @override Widget build(BuildContext context) { //下ナビだけ固定、appBarとbodyだけスクリーンを切り替え return Scaffold( //アプリバー appBar: _userHomeAppBar.elementAt(_selectedIndex), //コンテンツ body: _userHomeBody.elementAt(_selectedIndex), //下ナビゲーションバー bottomNavigationBar: BottomNavigationBar( type: BottomNavigationBarType.fixed, items: [ //呼ぶ BottomNavigationBarItem( icon: Stack( overflow: Overflow.visible, children: <Widget>[ Icon(IconCall.iconCall), Positioned( right: -15.0, child: Container( padding: EdgeInsets.all(1), decoration: new BoxDecoration( color: Colors.amber[800], borderRadius: BorderRadius.circular(10), ), constraints: BoxConstraints( minWidth: 20, minHeight: 20, ), child: new Text( '10', //通知の数 style: new TextStyle( color: Colors.white, fontSize: 9, fontWeight: FontWeight.bold, ), textAlign: TextAlign.center, ), ), ) ], ), title: Text('呼ぶ'), ), //探す BottomNavigationBarItem( icon: Icon(Icons.search), title: Text('探す'), ), ], currentIndex: _selectedIndex, selectedItemColor: Colors.black87, onTap: _onItemTapped, ), ); } }

▼問題の「探す」のクラス

//appBarに返す class GuestSearchAppBar extends StatefulWidget implements PreferredSizeWidget { GuestSearchAppBar({Key key}); Size get preferredSize => Size.fromHeight(40.0); _GuestSearchAppBarState createState() => _GuestSearchAppBarState(); } class _GuestSearchAppBarState extends State<GuestSearchAppBar> { @override Widget build(BuildContext context) { return AppBar( title: Container( padding: EdgeInsets.only(right: 12.0, left: 10.2), height: 80, ), backgroundColor: Colors.white, bottom: TabBar( tabs: _tab, ), ); } } //bodyに返す class SearchCast extends StatelessWidget { @override Widget build(BuildContext context) { return TabBarView(children: <Widget>[ TabPage(title: 'Car', icon: Icons.directions_car), TabPage(title: 'Bicycle', icon: Icons.directions_bike), TabPage(title: 'Boat', icon: Icons.directions_boat), ]); } } //TabPageの中身 class TabPage extends StatelessWidget { final IconData icon; final String title; const TabPage({Key key, this.icon, this.title}) : super(key: key); @override Widget build(BuildContext context) { final TextStyle textStyle = Theme.of(context).textTheme.display1; return Center( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Icon(icon, size: 64.0, color: textStyle.color), Text(title, style: textStyle), ], ), ); } }

このファイルから

Undefined name '_tab'.

Try correcting the name to one that is defined, or defining the name.

というエラーが出ます。(別クラスから指定しているのが原因なのは何となくわかるのですが)

Flutter初心者なもので、対処法がわからず困っています。
どのようにすれば実現可能なのでしょうか?

このような場合、例えばappBarを捨てて、bodyにまとめて上ナビバーも独自で作っても良いものなのでしょうか?
もし情報が足りなければ言ってください。よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

まず大前提として、タブを使うためにはTabControllerが必要になります。
以下のように、ScaffoldDefaultTabControllerで囲むと良いと思います。

dart

1return DefaultTabController( 2 length: 3, 3 child: Scaffold( 4 appBar: ... 5 body: ... 6 bottomNavigationBar: ...

次に発生しているエラーについてですが、_tabという変数が定義されてないということなので、問題がなければ、以下のようにAppBar内にベタ書きしてしまって良いと思います。

dart

1class _GuestSearchAppBarState extends State<GuestSearchAppBar> { 2 final List<Tab> _tabs = [ 3 Tab(child: Text("Car")), 4 Tab(child: Text("Bycicle")), 5 Tab(child: Text("Boat")) 6 ]; 7 8 9 Widget build(BuildContext context) { 10 return AppBar( 11 title: Container( 12 padding: EdgeInsets.only(right: 12.0, left: 10.2), 13 height: 80, 14 ), 15 backgroundColor: Colors.white, 16 bottom: TabBar( 17 tabs: _tabs, 18 ), 19 ); 20 } 21}

もし、タブを他の場所で定義したいというのであれば、以下のようにコンストラクタで受け取る方法があります。

dart

1class GuestSearchAppBar extends StatefulWidget implements PreferredSizeWidget { 2 final List<Tab> tabs; 3 4 GuestSearchAppBar({ 5 Key key, 6 this.tabs, 7 }); 8 9 Size get preferredSize => Size.fromHeight(48.0); 10 _GuestSearchAppBarState createState() => _GuestSearchAppBarState(); 11} 12 13class _GuestSearchAppBarState extends State<GuestSearchAppBar> { 14 15 Widget build(BuildContext context) { 16 return AppBar( 17 title: Container( 18 padding: EdgeInsets.only(right: 12.0, left: 10.2), 19 height: 80, 20 ), 21 backgroundColor: Colors.white, 22 bottom: TabBar( 23 tabs: this.widget.tabs, 24 ), 25 ); 26 } 27}

この場合、以下のように初期化時にタブのリストを渡す必要があります。

dart

1 GuestSearchAppBar( 2 tabs: [ 3 Tab(child: Text("Car")), 4 Tab(child: Text("Bycicle")), 5 Tab(child: Text("Boat")) 6 ], 7 ),

最後に、

このような場合、例えばappBarを捨てて、bodyにまとめて上ナビバーも独自で作っても良いものなのでしょうか?

という質問ですが、それも全然アリだと思います。
その場合、以下のようにColumnを使ってTabBarTabBarViewを並べることになると思います。

dart

1class TabExamplePage extends StatelessWidget { 2 final List<Tab> _tabs = [ 3 Tab(child: Text("Car")), 4 Tab(child: Text("Bicycle")), 5 Tab(child: Text("Boat")) 6 ]; 7 8 final List<Widget> _contents = [ 9 Center(child: Icon(Icons.directions_car)), 10 Center(child: Icon(Icons.directions_bike)), 11 Center(child: Icon(Icons.directions_boat)), 12 ]; 13 14 15 Widget build(BuildContext context) { 16 return DefaultTabController( 17 length: 3, 18 child: Scaffold( 19 appBar: AppBar(), 20 body: Column( 21 children: [ 22 TabBar(tabs: _tabs), 23 Expanded( 24 child: TabBarView( 25 children: _contents, 26 ), 27 ), 28 ], 29 ), 30 ), 31 ); 32 } 33} 34

投稿2020/09/09 13:10

nskhei

総合スコア704

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Yariii

2020/09/09 16:33

ご回答ありがとうございます。 なるほど、いろいろ対応策があって安心しました。勉強しているうちに何故かappbarはないといけないみたいな固定概念を持ってしまってて、それも拭えてよかったです^^; 具体的に書いていただいて大変勉強になりました。ありがとうございました...!m_ _m
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問