Persistent-Bottom-Navigation-Bar icon indicating copy to clipboard operation
Persistent-Bottom-Navigation-Bar copied to clipboard

Disable or Hide bottom navigation bar on few screens of the app using DIY NAVIGATOR SOLUTION

Open FaizanKamal7 opened this issue 4 years ago • 7 comments

I want to disable or hide the bottom navigation bar on few screens of the app using DIY NAVIGATOR SOLUTION. How can I achieve it?

Like if I go inside AllCtgView (It is the class that I'm opening inside TabNavigator upon clicking a button inside the bottom navigation bar), I want the navigation bar to hide whenever any screen inside the AllCtgView class showed up.

MyApp Class
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: BaseHomeView(),
    );
  }
}

BaseHomeView class

/////////////////////////////////////////////////////////////////////////////
/// DIY NAVIGATOR SOLUTION
////////////////////////////////////////////////////////////////////////////

class BaseHomeView extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => BaseHomeViewState();
}

class BaseHomeViewState extends State<BaseHomeView> {
  String _currentPage = "Page1";
  List<String> pageKeys = ["Page1", "Page2", "Page3", "Page4", "Page5"];
  Map<String, GlobalKey<NavigatorState>> _navigatorKeys = {
    "Page1": GlobalKey<NavigatorState>(),
    "Page2": GlobalKey<NavigatorState>(),
    "Page3": GlobalKey<NavigatorState>(),
    "Page4": GlobalKey<NavigatorState>(),
    "Page5": GlobalKey<NavigatorState>(),
  };
  int _selectedIndex = 0;

  void _selectTab(String tabItem, int index) {
    if (tabItem == _currentPage) {
      _navigatorKeys[tabItem].currentState.popUntil((route) => route.isFirst);
    } else {
      setState(() {
        _currentPage = pageKeys[index];
        _selectedIndex = index;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    final _deviceSize = MediaQuery.of(context).size;
    return WillPopScope(
      onWillPop: () async {
        final isFirstRouteInCurrentTab =
            !await _navigatorKeys[_currentPage].currentState.maybePop();
        if (isFirstRouteInCurrentTab) {
          if (_currentPage != "Page1") {
            _selectTab("Page1", 1);

            return false;
          }
        }
        // let system handle back button if we're on the first route
        return isFirstRouteInCurrentTab;
      },
      child: Scaffold(
        body: Stack(children: <Widget>[
          _buildOffstageNavigator("Page1"),
          _buildOffstageNavigator("Page2"),
          _buildOffstageNavigator("Page3"),
          _buildOffstageNavigator("Page4"),
          _buildOffstageNavigator("Page5"),
        ]),
        bottomNavigationBar: CurvedNavigationBar(
          color: Colors.white,
          backgroundColor: colorBlueLightShade,
          buttonBackgroundColor: Colors.white,
          onTap: (int index) {
            _selectTab(pageKeys[index], index);
          },
          index: _selectedIndex,
          items: <Widget>[
            Icon(FontAwesomeIcons.bars, size: _deviceSize.height * 0.02),
            Icon(FontAwesomeIcons.bars, size: _deviceSize.height * 0.02),
            Icon(FontAwesomeIcons.heart, size: _deviceSize.height * 0.02),
            Icon(FontAwesomeIcons.shoppingCart,
                size: _deviceSize.height * 0.02),
            Icon(FontAwesomeIcons.bars, size: _deviceSize.height * 0.02),
          ],
          // type: BottomNavigationBarType.fixed,
        ),
      ),
    );
  }

  Widget _buildOffstageNavigator(String tabItem) {
    return Offstage(
      offstage: _currentPage != tabItem,
      child: TabNavigator(
        navigatorKey: _navigatorKeys[tabItem],
        tabItem: tabItem,
      ),
    );
  }
}
TabNavigator class below
class TabNavigatorRoutes {
  static const String root = '/';
  static const String detail = '/detail';
}
class TabNavigator extends StatelessWidget {
  TabNavigator({this.navigatorKey, this.tabItem});
  final GlobalKey<NavigatorState> navigatorKey;
  final String tabItem;

  @override
  Widget build(BuildContext context) {
    Widget child;
    if (tabItem == "Page1")
      child = HomeView();
    else if (tabItem == "Page2")
      child = AllCtgView();
    else if (tabItem == "Page3")
      child = FavouriteProductsView();
    else if (tabItem == "Page4")
      child = CartView();
    else if (tabItem == "Page5") child = HomeView();

    return Navigator(
      key: navigatorKey,
      onGenerateRoute: (routeSettings) {
        return MaterialPageRoute(builder: (context) => child);
      },
    );
  }
}

FaizanKamal7 avatar May 26 '21 08:05 FaizanKamal7

I am guessing you mean after accessing the AllCtgView(), all the pages you access after it should have no bottom nav bar.

You want to do something like for every place that you navigate in that page: Navigator.of(context, rootNavigator: true).pushNamed("/route"); and Navigator.of(context, rootNavigator: true).push(MaterialPageRoute(builder: (context) => SecondRoute()),);

The key to having full screen back is saying that "rootNavigator:true"

Kickbykick avatar May 26 '21 15:05 Kickbykick

I am guessing you mean after accessing the AllCtgView(), all the pages you access after it should have no bottom nav bar.

You want to do something like for every place that you navigate in that page: Navigator.of(context, rootNavigator: true).pushNamed("/route"); and Navigator.of(context, rootNavigator: true).push(MaterialPageRoute(builder: (context) => SecondRoute()),);

The key to having full screen back is saying that "rootNavigator:true"

But where to do it though? Should I do it in TabNavigator class inside the onGenerateRoute? Or somewhere else? Can you please edit the part of the code where I have to write it and share it with me, please

FaizanKamal7 avatar May 26 '21 17:05 FaizanKamal7

Are you trying to do this after you get to the AllCtgView() or are you trying to do that on the base layer of the bottom nav bar.

Just a little confused. In my head, I am thinking after you navigate to the AllCtgView(),page, you can still see the bottom nav bar but when you click anything inside that particular page, it disappears. Is this correct?

Kickbykick avatar May 26 '21 18:05 Kickbykick

Are you trying to do this after you get to the AllCtgView() or are you trying to do that on the base layer of the bottom nav bar.

Just a little confused. In my head, I am thinking after you navigate to the AllCtgView(),page, you can still see the bottom nav bar but when you click anything inside that particular page, it disappears. Is this correct?

Brother forget about AllCtgView(). Let me tell you what I'm actually trying to do. I understand that using the above method we will be able to show the bottom navigation bar to all the screens of the app. There are almost 30 screens in my app. But on few screens like the login screen, cartview screen, orderview screen, and a couple of others, I don't want to show the bottom navigation bar there. I just want to hide it on these specific screens. As I proceed to pass any of these screens, the bottom navigation bar should re-appear. I'm a bad explainer. I hope you got my point

FaizanKamal7 avatar May 26 '21 18:05 FaizanKamal7

@Kickbykick Brother can you help me with that? i'm still struggling

FaizanKamal7 avatar May 28 '21 12:05 FaizanKamal7

I apologize for the later reply,

So for the login screen, this screen is meant to come before your main page. What you should do for this screen is to not have it be under the scaffold that has the bottom navigation bar.

What I would usually do is have a boolean that checks if the user is authenticated already

if(authenticated){
return LoginScreen();
} else {
return HomeScreen(); // This screen now starts the navigation bar
}

For the CartView and the OrderView screen, anytime a user clicks a button on those screens, you want to do this -> Navigator.of(context, rootNavigator: true).push(MaterialPageRoute(builder: (context) => CartView()),);

And then when the user wants to come out of those screens, if you want your bottom navigation bar back, the only way I can think of is Navigator.pop(context); then Push the new page on top of it. so:

Navigator.pop(context)
Navigator.of(context).push(MaterialPageRoute(builder: (context) => BackToMenu()),)

or if you are using named routes

Navigator.popAndPushNamed(context, '/screen4');

Kickbykick avatar May 28 '21 16:05 Kickbykick

I am guessing you mean after accessing the AllCtgView(), all the pages you access after it should have no bottom nav bar.

You want to do something like for every place that you navigate in that page: Navigator.of(context, rootNavigator: true).pushNamed("/route"); and Navigator.of(context, rootNavigator: true).push(MaterialPageRoute(builder: (context) => SecondRoute()),);

The key to having full screen back is saying that "rootNavigator:true"

Yes that's worked, Thanks for sharing the most valuable info

samrat19 avatar Aug 16 '21 14:08 samrat19