Almost any app that you design or develop will use some type of navigation.
There are three types of navigation that are common to all apps – stack, tab, and drawer navigation.
Flutter supports all three types, and implementing them is similar to how you do it in other apps. But I found it super smooth to build navigation into my Flutter app.
In this article, we'll build a Flutter app that uses all three types of navigation in a single app so you can learn how they work.
Types of Navigation
As I mentioned above, there are three main types of navigation that you might use in your apps. Again, they are:
- Stack Navigation
- Tab Navigation
- Drawer Navigation
Let's understand how each one works.
Picture a deck of cards, where you can add or remove cards from the top of the stack. Stack Navigation in Flutter works in a similar fashion. It helps you navigate between pages or screens by stacking new pages on top of existing ones.
When you move to a new screen, the current screen is pushed onto the navigation stack, and when you return, the top screen is popped off the stack.
This navigation type is commonly used for hierarchical and linear flows within an app.
Tabs are a staple of mobile app navigation, allowing users to quickly switch between different sections or views without losing their current context.
Flutter makes it easy to implement tabbed navigation with its built-in widgets, such as TabBar and TabBarView. By using these widgets, you can create a beautiful and functional tab navigation experience, perfect for organizing content into logical sections.
You also have the freedom to customize the appearance of your tabs, making it simple to create a unique look and feel for your app.
The Drawer Navigation pattern, also known as the "hamburger menu" or "side menu," is a popular navigation style in mobile apps. It consists of a hidden panel that slides out from the side of the screen, revealing a menu with various navigation options.
This space-saving technique keeps your app's main content visible while providing easy access to additional features or sections.
Let's start building the app and see how to implement each of these navigation features.
How to Create the Project
Instead of creating a new project every time from scratch, I've created a boilerplate app and uploaded in GitHub. You can pull the code and run. I hope that makes creating this project a bit simpler.
Navigate to the folder where you want to create your project in the terminal and run the following command.
Navigate to the
Flutter-Boilerplate folder and run the
flutter pub get command to install the dependencies.
That's it. We've got our dependencies installed.
Open the project in Visual Studio Code by running the
code ./ command in the terminal.
Start your emulator/connect your device and press
F5 in VS Code to run your app.
At the moment, the app will just contain an empty screen as shown in the below screenshot.
Let's build all 3 types of navigation into our app.
But before that, let's see what our final app will look like:
We'll have both drawer and tab navigators at the top. Pressing on the button in the first tab will take us to the next page via the stack navigator.
How to Build the Tab Navigation
Let's begin with building the tab navigator. Let's assume the tab will be on the home page (ideally that's where it would be).
Create a new file named
tab.dart in the
lib/ directory. Add the following code:
In the above code, we're creating a class named
HomePage. In the build method, we return the
DefaultTabController widget, which is basically a tab view. We define that we need 3 tabs in the
At the bottom of the
appBar property we have defined icons for each tab (Phone, Tablet, and Computer icons). Below that we define the
body property with a
TabBarView rendering all the tabs inside it.
Immediately when you paste in the above code, you'll notice lot of errors being highlighted in your VS Code editor.
This is because, if you look at the top four lines, the first line is the import of Flutter's Material UI package and the other three are imports from the user defined files. But we haven't created them yet. So, your code editor will throw an error in those lines and at the last three lines where we call
Tab3() (because, these classes are imported from those files). Let's resolve this issue now.
Create a new folder named
tabs inside the
lib/ directory and create three files named
Copy the below content into the
Copy the below content into the
Copy the below code into the
If you look at the code for all three files, you'll notice everything is the same except that the first tab file (
tab1.dart) has an additional button called "Disclose Secret". Pressing that will navigate the user to the
/secret route. It won't throw any error as this route has not been defined yet. The other two files (
tab3.dart) will show only the text.
All the errors you saw in the
tab.dart file will be resolved now. But if you run your app, you will not notice any changes in the output. This is because we have just created the tab layout and we haven't mapped it to our
Add the following line at the top of the
home: const MyHomePage(title: 'Home') with
home: const HomePage(), in the
build method of the
Save the file and run your app. You should be able to see the tab layout on your screen now.
Don't press the "Disclose Secret" button. If you press it, it will throw an error. Because, as I mentioned earlier, we set up a route navigation in the
onPress property of this button, but the route is not yet defined.
"Let's click that and see what happens"...
Hopefully, this thought will have entered your mind by now. It's not a mistake, it's human nature. We're curious to explore the things even if they're not recommended to do.
By the way, if you do that you'll see the following error (Exception in programming terminology):
In a nutshell, this error screenshot describes that the provided route does not exist.
How to Build the Drawer Navigation
Our next target is to add the drawer navigation. But before that, we have to create two files:
drawer.dart: to show the Navigation Drawer
about.dart: an option will be provided on the Drawer Navigator to navigate here
drawer.dart file inside the
lib/ directory and not inside the
tab/ directory. The
tab/ directory is only for tabs and we don't need to touch that further as we're done with the tabs. Copy the below code into the
In this file, we define the class named
MyDrawer. In the
build method we render the
Drawer widget with
About options in the list. Clicking on those options will navigate us to the appropriate routes.
about.dart file in the same directory and copy the below code:
In this file, we create a class named
About which returns a
Scaffold widget containing the drawer which we defined right before this file. The
appBar and the
body will show the text "About".
Again, you'll not be able to see these changes immediately in the app. This is because we haven't linked it into the
Before we link them, we have one item in our backlog. Let's finish it and come back to linking them all together.
Create a file named
secret.dart in the
lib/ directory and copy the below code:
In this file, we have created a class named
SecretPage and returned just a
Text in the
body. Nothing fancy here. It's a super simple Flutter widget.
Our backlog item is also done. This is what you've been waiting for: we're going to define our routes now.
main.dart file and add the following imports at the top of the file:
build method of the
MyApp class with the below code:
In the above code, you can see we're defining the MaterialApp to contain routes. They're defined as key-value pairs, mapping a route with a Widget. We have defined three routes:
/about– the route for the drawer navigator
/home– the route for the tab navigator
/secret– the route for the stack navigator
We have set the initial route to be
/home, which has the tab navigator.
Run the app and you should be able to see the following output on your device:
On pressing the "Disclose Secret" button you'll be taken to the Secret page which we created (ideally it does not have a secret). You should also be able to scroll through the tabs smoothly.
By now, I hope you will have noticed an error here. If not, here's what it is: the back button is shown on the first screen of our app.
"Why would we need to show the back button on the first screen?"
That's an error and we have to resolve it. Press the back button and let's see what happens. Hopefully, you see what I saw. The back button was hidden and we see just the "Home" title in the
appBar (similar to the below screenshot):
But there's an another issue on the same screen. Hopefully you saw that too. If not, don't worry, I'll reveal it right here.
"Can you access the drawer navigator by any means?"
But fortunately, the fix for the above two issues is the same. If we fix the second issue, the first issue will automatically be fixed.
That's great. But how do we fix the second issue?
You have to show the drawer navigator button (Hamburger icon) on the top left. This will eventually hide the back button.
tab.dart file and import the drawer file at the top of this file.
Add the following line inside the
Scaffold widget of the
And that's it!
Here's the output you can see when you run your app:
In this article, you've learned how to implement navigation in a Flutter app. We've included all three types of navigation in a single app in this tutorial for educational purposes. Ideally, you wouldn't do this with any real app you're building. Most apps will be built on either one or two types of navigation.
This repo has my code. You can use it for your reference.