flutterdarttabbarflutter-navigationflutter-bottomnavigation

Navigation within Tab view body Flutter


The app contains TabBar as well as BottomNavigationBar. When I tried to navigate within the body of tab bar view it navigates full screen.

This is the result I am trying to get when clicked on button- Expected Result

But I am getting this Current Output

Here I have attached the code-

 Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(
            title: new Text("Traveler"),
            bottom: new TabBar(controller: _controller, tabs: <Tab>[
              new Tab(text: "NEW"),
              new Tab(text: "HOTELS"),
              new Tab(text: "FOOD"),
              new Tab(text: "FUN"),
            ]),
          ),
          body: new TabBarView(
            controller: _controller,
            children: <Widget>[
              new NewPage(_index),
              new HotelsPage(_index),
              new FoodPage(_index),
              new FunPage(_index),
            ],
          ),
          bottomNavigationBar: new BottomNavigationBar(
              currentIndex: _index,
              onTap: (int _index) {
                setState(() {
                  this._index = _index;
                });
              },
              items: <BottomNavigationBarItem>[
                new BottomNavigationBarItem(
                  icon: new Icon(Icons.home),
                  title: new Text("Home"),
                ),
                new BottomNavigationBarItem(
                  icon: new Icon(Icons.favorite),
                  title: new Text("Favorites"),
                ),
              ]),
        );
      }
    }
    
    class NewPage extends StatelessWidget {
      final int index;
    
      NewPage(this.index);
    
      @override
      Widget build(BuildContext context) {
        return new Center(
          child: RaisedButton(
            onPressed: (){
               Navigator.push(context,MaterialPageRoute(builder: (context)=>InsideTabViewPage()), );
            },
            child: new Text('NewPage, index: $index')),
        );
      }
    }
    
   

Solution

  • You can achieve this by creating a new Navigator widget that sits somewhere under the main app navigator,

    Here is test example:

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MaterialApp(
          debugShowCheckedModeBanner: false,
          theme: ThemeData.dark().copyWith(
            elevatedButtonTheme: ElevatedButtonThemeData(
                style: ButtonStyle(
              backgroundColor: MaterialStateProperty.all(Colors.blueGrey[800]),
            )),
          ),
          home: MyApp()));
    }
    
    //Store this globally
    final GlobalKey<NavigatorState> _navKey = GlobalKey<NavigatorState>();
    
    class MyApp extends StatefulWidget {
      MyApp({Key? key}) : super(key: key);
    
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
      late final TabController _tabController;
      @override
      void initState() {
        _tabController = TabController(length: 2, vsync: this);
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Nested Navigator'),
            bottom: TabBar(
              controller: _tabController,
              tabs: [
                Tab(
                  child: Text('First Tab'),
                ),
                Tab(
                  child: Text('Second Tab'),
                ),
              ],
            ),
          ),
          bottomNavigationBar: BottomNavigationBar(
            items: [
              BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
              BottomNavigationBarItem(
                  icon: Icon(Icons.favorite), label: 'Favorites'),
            ],
          ),
          body: Navigator(
            key: _navKey,
            onGenerateRoute: (_) => MaterialPageRoute(
              builder: (_) => TabBarView(
                controller: _tabController,
                children: [
                  FirstPage(),
                  SecondPage(),
                ],
              ),
            ),
          ),
        );
      }
    }
    
    class FirstPage extends StatelessWidget {
      const FirstPage({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text('First Page'),
                ElevatedButton(
                    onPressed: () {
                      _navKey.currentState!.push(
                        MaterialPageRoute(
                          builder: (_) => SubFirstPage(),
                        ),
                      );
                    },
                    child: Text('Go to Nested Page 1'))
              ],
            ),
          ),
        );
        ;
      }
    }
    
    class SecondPage extends StatelessWidget {
      const SecondPage({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text('Second Page'),
                ElevatedButton(
                  onPressed: () {
                    _navKey.currentState!.push(
                      MaterialPageRoute(
                        builder: (_) => SubSecondPage(),
                      ),
                    );
                  },
                  child: Text('Go to Nested Page 2'),
                )
              ],
            ),
          ),
        );
      }
    }
    
    class SubFirstPage extends StatelessWidget {
      const SubFirstPage({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('First Nested Page'),
          ),
          body: Center(
            child: Text('From First Page'),
          ),
        );
      }
    }
    
    class SubSecondPage extends StatelessWidget {
      const SubSecondPage({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Second Nested Page'),
          ),
          body: Center(
            child: Text('From Second Page'),
          ),
        );
      }
    }
    

    And the result is:

    enter image description here

    You can read more about nested navigation in Navigator 1.0 API here