Search code examples
flutternavigationpersistencebottomnavigationview

Flutter - Persisting BottomNavigationBar - how not to show on some pages?


My implementation:

main.dart: - it builds multi scaffold (Bottom navigation bar is being created on all screens above UI tree)

runApp(MaterialApp(
    debugShowCheckedModeBanner: false,
    title: "WP-seven",
    builder: (context, child) {
      return Scaffold(
        bottomNavigationBar: NavyBottomBar(navigator: (child.key as GlobalKey<NavigatorState>)),
        body: child,
      );
    },
    home: NewsList(0),
));

NavyBottomBar.dart: separated class for the navBar widget. Here we have a Global navigator key that is used in main.dart to connect to every child's navigator(child is every screen widget.)

final GlobalKey<NavigatorState> navigator;

So there is also a logic to open pages, but the code above is enough to show the bottomNavigationBar on every screen and to be able to navigate.

The problem is that I don't need this bottom navigation on every screen, there should be a way to switch off the navigationBar on some screens.

Probably there is a different approach to achieve this result..?


Solution

  • I've found a solution and it works great, but first a few words about the above:

    Hero is not an option, because it does not support all types of navigation, like pushReplacement for example and I had a bug with animation in my NavigationBar while using it, probably because hero has built-in animation, too.

    Solution:

    • I've created a new screen called homePage (something like a hub for navigation).
    • There we have a thing called PageStorageBucket which is useful for storing per-page state that persists across navigations from one page to another. enter link description here

    homePage.dart:

    Widget newsList;
    Widget favorites;
    Widget profile;
    Widget answers;
    
    List<Widget> pages;
    Widget currentPage;
    
    final PageStorageBucket bucket = PageStorageBucket();
    
    @override
    void initState() {
      newsList = NewsList(isFavorite: 0);
      favorites = NewsList(isFavorite: 1);
      profile = Profile(userID: widget.userID);
      answers = Answers();
    
      pages = [newsList, favorites, profile, answers];
    
      currentPage = newsList;
      super.initState();
    }
    

    So we've added a number of Widgets(Screens) to a PageStorage bucket and then we use it in Scaffold of homePage.. there is even a place for it.

    @override
    Widget build(BuildContext context) {
    return Scaffold(
      body: PageStorage(
        child: currentPage,
        bucket: bucket,
      ),
      bottomNavigationBar: BottomNavyBar(
        currentIndex: currentTab,
        onItemSelected: (int index) async {
            setState(() {
              currentTab = index;
              currentPage = pages[index];
            });
        },
        items: [
          BottomNavyBarItem(
              icon: Icon(Icons.menu),
              title: Text('Новости'),
              activeColor: Colors.blue,
              inactiveColor: Colors.black
          ),
          BottomNavyBarItem(
              icon: Icon(Icons.favorite_border),
              title: Text('Избранное'),
              activeColor: Colors.red,
              inactiveColor: Colors.black
          ), 
         ],
        ),
       );
      }
     }
    

    It works perfectly.

    • homePage Scaffold is persistent and does not re-render when redirecting to another page, so we can use nav bars with animations and anything else.
    • We can choose what pages will be included into this scope.
    • We can still use Navigator.push and else inside of these screens
    • It is possible to use multi-scaffold like when you need different appBars, just delete appBar of homePage and it will use an appBar from the opened screen.