Flutter Navigation : Maintaining Navigation Stack in each Tab while Navigating through BottomNavigationBar

Shubham Soni
Flutter Community
Published in
5 min readNov 28, 2020

Flutter is fascinating and there’s no competition when it comes to developing beautiful UIs for the mobile. Although once in a while, we stuck on simple things that make our heads turned around. Like I did when I had to maintain the state of individual tabs while navigating through BottomNavigationBar. You can find a great tutorial on the same here, written and explained very well. Even though the article is absorbing, I found it a little complex(Personal Opinion). Then, I decided to do it another way round. I’m not saying mine is better, it’s just my way of doing things.

We’re going to create a BottomNavigationBar containing four tabs. Each tab will have Listview containing multiple items and each item will navigate to a separate route when tapped. What we have to do is to have maintained the current navigation stack and state of the tab while navigating through the BottomNavigationBar.

Step By Step :

1) Make a BottomNavBar

2) Each BottomNavBar Tab will contain a ListView

3) ListView will have a list of items.

4) Each Item in the ListView will navigate to a separate route

5) Maintain the state of the ListView navigation stack while navigating through BottomNavBar

Enough talk lets just jump into the code and see how it’s done. Before proceeding please make sure you are familiar with these things:

Here’s What we gonna do

Let’s Start

It's all about widgets so let's create our root widget App containing MaterialApp with Homepage() as the home widget.

Now we’ll create a StatefulWidget called HomePage which will contain the BottomNavigationBar and an IndexedStack so that we can navigate between tabs while maintaining state of each tab. If you don’t know much about IndexedStack please try looking at the docs once.

IndexedStack is Stack that shows a single child from a list of children while maintaining the state of each children in the stack.

Here we’re using _pageIndex to keep track of the active index in the IndexedStack which is being shown to the user. Our IndexedStack contains four tabs and each tab shows aNavigatorPage as its child.Hope everything is clear up until now.

So, now let’s look at the NavigatorPage.

Things we’re doing in NavigatorPage

  • We’re using Navigator and MaterialPageRoute for navigating (Will explain why)
  • A ListView containing a list of items.
  • Each item when clicked navigate to it’s own DetailRoute .

So at last we’ll see DetailRoute implementation.

There’s not much happening here, we’re just showing up an AppBar with Route number on it and a TextField in center with TextEditingController that we’re receiving from NavigatorPage.

Earlier I mentioned that we’re using Navigator and MaterialPageRoute to navigate in NavigatorPage. You can actually remove both of them, then NavigatorPage will look like this:

But there’s a problem with this approach, see what we got vs what we want.

what we want VS what we have (Without Navigator and MaterialPageRoute)
what we want VS what we got

Did you notice the BottomNavigationBar in both of them? As you can see if we do not use Navigator and MaterialPageRoute we’ll end up having DetailRoute without BottomNavigationBar. Because when we don’t use Navigatorthen whenever we push any route, the route will be stacked on the default Navigator that comes with MaterialApp.

One last thing :

We have completed almost everything that we have discussed at the start of this article. Now there’s only one issue with our code. See this

Whenever we navigate to DetailRoute and we press the back button, our app closes suddenly. To fix this issue we need to use WillPopScope and GlobalKey. Try to do this by yourself, here are some hints for you:

  • Go check WillPopScope and GlobalKey in Flutter docs.
  • WillPopScope is a widget that registers a callback to veto attempts by the user whenever he/she presses back button.
  • GlobalKey will help you get the BuildContext of current DetailRoute.

If you solved this all by yourself then congratulations on your victory. If not then don’t worry you have tried atleast and here’s an applaud from my side for giving it a shot.

Now, let’s come to the solution,

  • Put WillPopScope as a parent widget to IndexedStack.
  • Declare a map containing four GlobalKeys inside HomePage ,one for each of the tabs.
  • Pass an asynchronous method to onWillPop parameter of WillPopScope . onWillPop receives a callback that get’s called whenever user presses back button.
  • We have to make sure the correct route pops out of the widget tree on back button tap.
  • Pass GlobalKeys to NavigatorPage
  • Use GlobalKeys received from HomePage as key to the NavigatorPage.

This is what our HomePage code now looks like after all these changes.

And this will the updated NavigatorPage code.

☀️ Conclusion :

Although as a flutter developer we use Navigator (push & pop) very often but there are few use cases when we actually use Navigator as a widget and this one is the perfect scenario to use Navigator. Also we learned about GlobalKey, MaterialPageRoute, WillPopScope etc. I tried to explain as good as I can, so please pardon me if I couldn’t and let me know where I can improve.

You can view or download the source code for this article from here

Thanks for reading. If you liked this one, you should follow me for the next one. 🙏

Thank to Flutter Community for all the awesome work they are doing on StackOverflow, Github and Pub.

If you have any questions, feel free to post them 👇.

Any feedback is welcome 😃.

If you enjoyed this story, you can support me by 👏 this.

You can also follow me on Twitter , Facebook or Instagram.

--

--

Shubham Soni
Flutter Community

Senior Executive @Ketto @Dart @Flutter @Java @Android, Editor @FlutterCommunity @CodeBurst.io, App Developer @Senior @Moderator @FlutterDeveloper