Organized Navigation Named Route in Flutter 2021

organized-navigation-named-route-in-flutter

Navigate pages with a named route in flutter is probably one of the most common methods to use when you create an application. Named route helps you organize the code and simply navigate between pages. Today, we are going to learn how to navigate between three screens: LoginHome, and Settings. Moreover, we will properly structure our folders and files, so they can be reused anywhere in your project. 

1. Create an Organized File Structure

Before we do any coding, we need to first structure our Navigation Route files and folders in the project. We are going to use a ‘VC’ model (V-views, C-controller) to manage our app flow.

Let’s start with creating folders and files in our flutter project. Inside our lib folder, we will create two files: route and views.

In the route folder, create a route.dart file. This file will be our controller for managing routes. 

In the views folder, create all page views names that you need to use. In our case, it will be a login.darthome.dart, and settings.dart files. 

Inside these files, you can design your pages however you want.

Note: Of course, we could just create one dart file, create all pages there, and load them at once. But I’m not really a fan of that. I prefer to have all pages as a separate file so we could quickly and easily access them.

This is how our result should looks like:

File structure for named route in flutter
File Structure

Great! Now, we are ready for the next step!

2. Create Named Route Controller

The first thing we will do is create a route controller inside our route.dart file.

  • import material design, and our previously created views. Then, create Route controller
import 'package:flutter/material.dart';

// Define Routes
import 'package:named_route/views/home.dart';
import 'package:named_route/views/login.dart';
import 'package:named_route/views/settings.dart';

// Control our page route flow
Route<dynamic> controller(RouteSettings settings) {

}

Note: package:named_route (name_route is the name of my app. You should place your own name)

Inside our controller() function, we will handle all page routes. We will use a switch statement with settings.name to have a logical controller. So, let’s first create const variables with names for our routes. To do so, we simply write const String [page_name] above our controller.

import 'package:flutter/material.dart';

// Define Routes
import 'package:named_route/views/home.dart';
import 'package:named_route/views/login.dart';
import 'package:named_route/views/settings.dart';

// Route Names
const String loginPage    = 'login';
const String homePage     = 'home';
const String settingsPage = 'settings';

// Control our page route flow
Route<dynamic> controller(RouteSettings settings) {

}

Note: Did you mentioned that I never used a slash ‘/’ on my route’s name? Okay, let me explain to you why I do not like having slashes in route’s name. The thins is when you use a slash ‘/’ – it’s called a “deep link“. Basically, it’s mean that if, for example, our Home Page name would be just ‘/’ and our Login Page ‘/login’. Even if use put initialRoute to Login Page (/login), it would first load and push Home Page (/) route and then Login Page (/login) because ‘/login’ comes after ‘/’. P.S Of course, it can be overwrite through onGenerateInitialRoutes, but it’s still uncomfortable.

Original source: “if the route was /a/b/c, then the app would start with the four routes /, /a, /a/b, and /a/b/c loaded, in that order. ” (Official link)

Anyways, let’s continue.

Next what we are going to do is create a switch statement inside our controller function.

import 'package:flutter/material.dart';

// Define Routes
import 'package:named_route/views/home.dart';
import 'package:named_route/views/login.dart';
import 'package:named_route/views/settings.dart';

// Route Names
const String loginPage    = 'login';
const String homePage     = 'home';
const String settingsPage = 'settings';

// Control our page route flow
Route<dynamic> controller(RouteSettings settings) {
  switch (settings.name) {
    case loginPage:
      return MaterialPageRoute(builder: (context) => LoginPage());
    case homePage:
      return MaterialPageRoute(builder: (context) => HomePage());
    case settingsPage:
      return MaterialPageRoute(builder: (context) => SettingsPage());
    default:
      throw('This route name does not exit');
  }
}

Note: Do not pay attention to errors that appeared. We will create our pages right now.

Fantastic! We completed this step and we are ready to move forward!

3. Create Login, Home, and Settings Pages

In this step, we are going to create a super simple and basic pages. We are not going to design any complex login, home, or settings pages since this is a tutorial for named route navigation.

The idea will be very simple:

  • ‘Login’ page – will be our first scene. We will have a button that navigates to a Home page.
  • ‘Home’ page – will be our second scene. We will have a floating button that navigates to a Settings page.
  • ‘Settings’ page – will be our third scene. This will be our last scene. We are not going to implement any further navigation (I think 2 will be enough for the tutorial).

Important: For all pages, we will create a Stateless widget. If your page needs to be dynamic (interact with user) e.g a form, any ongoing web request etc, you should probably use a Stateful widget instead. Click her to learn more from official Flutter website.

This is what we get:

Login.dart (Login Page)

import 'package:flutter/material.dart';
import 'package:named_route/route/route.dart' as route;

class LoginPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Login Page'),
      ),
      body: Center(
        child: ElevatedeButton(
          child: Text(
            'Login',
            style: TextStyle(color: Colors.white),
          ),
          onPressed: () => Navigator.pushNamed(context, route.homePage),
          color: Colors.blue,
        ),
      ),
    );
  }
}

Home.dart (Home Page)

import 'package:flutter/material.dart';
import 'package:named_route/route/route.dart' as route;

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home Page'),
      ),
      body: Center(
        child: Text('Hello, oflutter.com'),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.settings),
        onPressed: () => Navigator.pushNamed(context, route.settingsPage),
      ),
    );
  }
}

Settings.dart (Settings Page)

import 'package:flutter/material.dart';

class SettingsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Settings'),
      ),
      body: Center(
        child: Text('Hi, settings'),
      ),
    );
  }
}

Note: If you want to navigate to another page, first, we need to import ‘package:named_route/route/route.dart’ as route; Then, we can use route.[route_name] inside Navigator.pushNamed(context, route.settingsPage). This will allow us to use named route for navigation.

Awesome! Now, we are ready to do our last step. Link everything with main.dart file

4. Link everything with main.dart file

This is our last step. We need to link everything with main.dart file so our named navigation route work.

In our main.dart file, we are going to have a simple StatelessWidget that going to handle all our routes.

The first thing we need to do is to import our route controller, and then use

  • onGenerateRoute: route.controller
  • initialRoute: route.loginPage

inside our MaterialApp() widget.

This is our final result:

import 'package:flutter/material.dart';
import 'route/route.dart' as route;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primaryColor: Colors.blue,
      ),
      onGenerateRoute: route.controller,
      initialRoute: route.loginPage,
    );
  }
}

That’s pretty much it! I hope you found this article helpful! Leave your thought in the comments.


Q/A:

Q: How to use different animation when navigating between routes?
A: We used MaterialPageRoute() which uses a default animation. If you want to use different one, you can either use PageRouteBuilder() or CupertinoPageRoute().

Q: I create a new page, how can I navigate to another page?
A: First of all, you need to make sure that you added a new page to a route.dart file. Then, you can import ‘route/route.dart’ as route; and use route.myNewPage.

Q: How would you pass an argument while routing between pages?
A: Let’s assume we want to pass an argument from loginPage to homePage. To do so, we should first add argument request in our HomePage stateless widget. Like so:

...
class HomePage extends StatelessWidget {
  final Object argument;
  HomePage({this.argument});

 ....

}

Then, you would add settings.arguments option to Route<dynamic> controller(RouteSettings settings) for HomePage

......

// Control our page route flow
Route<dynamic> controller(RouteSettings settings) {
  switch (settings.name) {
    .....
    case homePage:
      return MaterialPageRoute(builder: (context) => HomePage(arguments: settings.arguments));
    .....
    
  }
}

.....

Finally, pass any objects e.g text, data when you use Navigator.pushNamed();

....

class LoginPage extends StatelessWidget {
....
        child: ElevatedeButton(
         ....
          onPressed: () => Navigator.pushNamed(context, route.homePage, arguments: 'My object As Text'),
         ....
        ),
      ),
    );
  }
}

To retrieve a data from HomePage, you would then just use: widget.argumets


You May Also Like

2 Comments

    1. Hi, thanks for your comment. I added an answer to the Q/A section on this post. Let me know if you have any other questions/problems.

Leave a Reply

Your email address will not be published. Required fields are marked *

2 × four =