Always show BottomNavigationBar

940 views Asked by At

Is there a way to show the BottomNavigationBar on every page? Currently the BottomNavigationBar disappears when pushing the button but I want the BottomNavigationBar to always be displayed even when routing to a new page. The following code shows my BottomNavigationBar and my detail page.

class BottomNavBar extends StatefulWidget {
  const BottomNavBar({Key? key}) : super(key: key);

  @override
  State<BottomNavBar> createState() => _BottomNavBarState();
}

class _BottomNavBarState extends State<BottomNavBar> {
  int currentIndex = 0;
  final screens = const [Home(), Search()];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: screens[currentIndex],
        bottomNavigationBar: BottomNavigationBar(
            type: BottomNavigationBarType.fixed,
            backgroundColor: bottomNav,
            unselectedItemColor: Colors.grey,
            selectedFontSize: 12,
            unselectedFontSize: 12,
            currentIndex: currentIndex,
            onTap: (index) => setState(() => currentIndex = index),
            items: const [
              BottomNavigationBarItem(
                  icon: Icon(
                    Icons.home_filled,
                    size: 28,
                  ),
                  label: 'Home'),
              BottomNavigationBarItem(
                  icon: Icon(
                    Icons.search_rounded,
                    size: 28,
                  ),
                  label: 'Search'),
            ]));
  }
}

My detail page:

class Home extends StatelessWidget {
  const Home({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
          child: IconButton(
        icon: const Icon(Icons.abc),
        onPressed: () {
          Navigator.push(
              context, MaterialPageRoute(builder: (context) => const Page1()));
        },
      )),
    );
  }
}

class Page1 extends StatelessWidget {
  const Page1({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
    );
  }
}
3

There are 3 answers

0
Alberto Malagoli On

You can use a Navigator widget to achieve this. Check the following code: Each NavigatorView creates its own Navigator instance. This allows each tab to manage its navigation stack independently while keeping the BottomNavigationBar in place. Inside each PrimaryView, pages are pushed onto the stack of its corresponding Navigator. This means navigating to new pages doesn’t affect the visibility of the BottomNavigationBar.

Code example:

import 'package:flutter/material.dart';

void main() {
  runApp(const AppView());
}

class AppView extends StatefulWidget {
  const AppView({super.key});

  @override
  State<AppView> createState() => _AppViewState();
}

class _AppViewState extends State<AppView> {
  int route = 0;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          body: IndexedStack(
            index: route,
            children: const [
              NavigatorView(child: PrimaryView(title: 'view 1')),
              NavigatorView(child: PrimaryView(title: 'view 2')),
              NavigatorView(child: PrimaryView(title: 'view 3')),
            ],
          ),
          bottomNavigationBar: NavigationBar(
            selectedIndex: route,
            onDestinationSelected: (index) {
              setState(() {
                route = index;
              });
            },
            destinations: const [
              NavigationDestination(
                label: '1',
                icon: Icon(Icons.home),
              ),
              NavigationDestination(
                label: '2',
                icon: Icon(Icons.star),
              ),
              NavigationDestination(
                label: '3',
                icon: Icon(Icons.info),
              ),
            ],
          )),
    );
  }
}

class NavigatorView extends StatelessWidget {
  final Widget child;

  const NavigatorView({
    super.key,
    required this.child,
  });

  @override
  Widget build(BuildContext context) {
    return Navigator(
      onGenerateRoute: (RouteSettings settings) {
        return MaterialPageRoute(
          builder: (BuildContext context) => child,
        );
      },
    );
  }
}

class PrimaryView extends StatelessWidget {
  final String title;
  const PrimaryView({
    super.key,
    required this.title,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.of(context).push(
              MaterialPageRoute(
                builder: (context) => const SecondaryView(),
              ),
            );
          },
          child: const Text('Details'),
        ),
      ),
    );
  }
}

class SecondaryView extends StatelessWidget {
  const SecondaryView({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Details'),
      ),
      body: const Center(
        child: Text('Details'),
      ),
    );
  }
}
2
rasityilmaz On

If you want to show this navigation bar on all pages, do not use the Scaffold you used in BottomNavBar on your other pages. Because with each new Scaffold you set the BottomNavigationBar parameter of other pages to empty.

0
Divyam Dhadwal On

Well, it should show on every page If all those pages (where you want to show this bar) have been put under the same Scaffold. Here's what I usually do:

Create a list that holds the pages you want to show bottomNavigationBar on :

List subScreens = [SubScreen1(), SubScreen2(), SubScreen3()]

Now, create a base page/screen which would render these subscreens like this:

return Scaffold(
     bottomNavigationBar: BottomNavigationBar(),
     body: subScreens[stateCounter],
 );

Now use this stateCounter as currentIndex to your BottomNavigationBar() as well as to also fetch the correct subscreen from the list.