# Nested Navigation In Flutter : Navigator Widget

## Introduction

A Navigator widget in Flutter is what we use to maintain a stack of routes and it plays a huge role in helping us to navigate between routes. The Navigator widget often works under the hood without us having to initialise it but there are certain use cases where we may have to do it manually. Most Flutter apps tend to use methods associated with `Navigator` like `push` and `pop` to move to other screens instead of defining it. This is because when we start our app with the `MaterialApp` widget, it will introduce a `Navigator` for us to use. In this article, we shall explore more about using multiple Navigators / Nested Navigation.

Nested navigation is mostly needed when we don't want to completely replace the current screen with a new screen. In such cases, what we'll be doing is pushing a screen only at certain intervals and keeping the rest of the screen intact. For example, the Instagram app.

In this article, you will be learning more about:

- Using multiple Navigator widgets
- Performing Nested navigation
- Using keys to access the desired Navigator

## Setting Up


- Let's start with an example where we have only one *Navigator* widget. Our class will have a `BottomNavigationBar` wrapped inside a `MaterialApp` and a `NestedScreen()` which acts like the body of the `BottomNavigationBar. To go forward, we will pass a navigator called `NavigatorKeys.navigatorKeyMain` to the `MaterialApp`. Refer to the code snipper given below to understand this better:

```
class NestedScreen extends StatelessWidget {
  NestedScreen({Key key}) : super(key: key);

  void _push(BuildContext context, String name) {
    Navigator.of(context).push(
      MaterialPageRoute(
        builder: (context) => Scaffold(
          appBar: AppBar(
            ...
          ),
          body: Center(
            ...
          ),
        ),
      ),
    );
    
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
         body: _home(context)
       );
  }

  Widget _home(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            GestureDetector(
              onTap: () => _push(context, 'Page 1'),
              child: Text(
                'Page A',
                style: TextStyle(fontSize: 50),
              ),
            ),
            GestureDetector(
              onTap: () => _push(context, 'Page 2'),
              child: Text(
                'Page B',
                style: TextStyle(fontSize: 50),
              ),
            )
          ],
        ),
      ),
    );
  }
}

```

> Here’s the [full source code](https://github.com/ntshTiwari/nested_nav) .

### With one Navigator widget

And this is how our screen looks like:

![Nested_Nav_Eg.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1636136300785/HlsvunMXWq.png)

If we click on *Page A* or *Page B* then we will notice that a new screen *Nested Screen* replaces the current screen, which is definitely not what we wanted.

![Nested_nav_gif_1.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1636136540002/yidzJBebN.gif)

### With two Navigator widgets


- Having two widgets can potentially be a hassle. So, to solve this problem we will have to introduce a new `Navigator` in the widget tree after the `BottomNavigatorBar` widget and use it which will cause the `Navigator` to only replace the body of the current screen. First lets add a function `_routeBuilders()` to our `NestedScreen` class and a `GlobalKey` variable as shown below:

```
class NestedScreen extends StatelessWidget {
  NestedScreen({this.navigatorKey, Key key}) : super(key: key);
  final GlobalKey<NavigatorState> navigatorKey;
   ...
Map<String, WidgetBuilder> _routeBuilders( BuildContext context ) {
    return {
      '/': (context) => _home(context),
      /// we only have one screen for now
    };
  }
   ...
}
```


- The function given above will manage routes for us.(Here we only have one screen) Now, add a new `Navigator` widget in the body of `NestedScreen` class as shown below:

```
class NestedScreen extends StatelessWidget {
   ...
@override
  Widget build(BuildContext context) {
    var routeBuilders = _routeBuilders(context);

    return Scaffold(
      body: Navigator(
        key: navigatorKey,
        initialRoute: NestedScreenRoutes.root,
        onGenerateRoute: (routeSettings) {
          return MaterialPageRoute(
              builder: (context) => routeBuilders[routeSettings.name](context));
        },
      ),
    );
  }
   ...
}
```


- In our newly introduced `Navigator` widget we will pass the `navigatorKey` as the key. This is how our widget tree looked before adding the `Navigator` widget:

![Nested_Nav_Widget_Tree_Before.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1636137325362/e8Tq6CZUI.png)


- And this is our new widget tree after adding the `Navigator` widget:

![Nested_Nav_Widget_Tree.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1636137071966/XFJAdDkGF.png)


- We can see a new Navigator widget in our NestedScreen class. Now. when we click on Page A or Page B we will notice that the `Nested Screen` replaces only the body of the current screen, which is what we wanted. Refer to the picture given below: 

![Nested_nav_gif_2.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1636137679545/6dg9RD_qq.gif)

### Decoding

Let's understand how to go about the decoding process in this segment. After adding a new `Navigator` widget, we will now have two `Navigator` widgets in our widget tree: One above the `BottomNavigatorBar` (in the `MaterialApp`) and one below the `BottomNavigatorBar`. After this, when we write `Navigator.of(context).push()`,  the nearest (above) `Navigator` widget is accessed and everything below it is replaced.  So, when we access the `Navigator` above the `BottomNavigatorBar`, it replaces the `BottomNavigatorBar`, but when we access the `Navigator ` below the `BottomNavigatorBar`, is holding cause any changes


But there can be cases when we would like to use the other `Navigator` widget, such as if we want to replace the entire current screen with a screen on clicking Page B and replace only a part of it on clicking Page A. To do this, we will have to access the `Navigator`  when we click on `Page B.

Let's see how can we do this.

### Use keys to access the desired Navigator

To access a desired Navigator, we will have to pass the respective context while performing operations. Based on whether *Page A* or *Page B* is clicked, we will get either the `context` from the `navigatorKey` variable or `NavigatorKeys.navigatorKeyMain` which is used at the start of the `MaterialApp` level. For this, we will change the `_push()` method of the `NestedScreen` class as shown below:

```
class NestedScreen extends StatelessWidget {
...
  void _push(BuildContext context, String name) {
    BuildContext _desiredContext;
    if (name == 'Page 1') {
      _desiredContext = navigatorKey.currentContext;
    } else {
      _desiredContext = NavigatorKeys.navigatorKeyMain.currentContext;
    }
    Navigator.of(_desiredContext).push(...);
  }
...
}
```

Now, if we click on Page A the lower `Navigator` widget will be accessed and only the body of the `BottomNavigationBar` will change. and by clicking on Page B, the above Navigator widget will be accessed and the entire current screen will change.

![Nested_nav_gif_3.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1636137901661/e25Ka-G_s.gif)

And that is how we use the desired `Navigator` widget from the widget tree!

## Conclusion

The main ingredient to nested navigation is a second Navigator widget. When we start with a `MaterialApp`, we will introduce a Navigator which we can use throughout the app as shown in this article.  When we call the `Navigator.method()`, then the nearest Navigator widget (above this widget in widget tree) is used and we can use keys to access the desired Navigator. Here’s the final project [link](https://github.com/ntshTiwari/nested_nav) .

Thanks for reading.

































