DEV Community

Cover image for Flutter: Advance Routing and Navigator Part 1
Nitish Kumar Singh
Nitish Kumar Singh

Posted on • Edited on

Flutter: Advance Routing and Navigator Part 1

Flutter: Advance Routing and Navigator (Part 1)

First of all, I am going to start with basic Routing. You can find the basic routing on flutter website also.

Core concepts and classes for managing multiple screens

  1. Route : A Route is an abstraction for a “screen” or “page” of an app, and a Navigator is a widget that manages routes.
  2. Navigator : Creates a widget that maintains a stack-based history of child widgets. A Navigator can push and pop routes to help a user move from screen to screen
  3. Material Page Route : A modal route that replaces the entire screen with a platform-adaptive transition.

What is platform-adaptive Transition ?

The Transition which you see when routing from one screen to other screens.

> For Android , the entrance transition for the page slides the page upwards and fades it in. The exit transition is the same but in reverse.

> For iOS , the page slides in from the right and exits in reverse. The page also shifts to the left in parallax when another page enters to cover it

This Transition happens because of MaterialPageRoute only. You can modify this transition also. To modify this transition you need to play with MaterialPageRoute or PageRouteBuilder.

Mobile apps typically display full-screen elements called “screens” or “pages”. In Flutter, these elements are called routes and they’re managed by a Navigator widget. The navigator manages a stack of Route objects and provides methods for managing the stack, like Navigator.push and Navigator.pop.

Example 1 : Simple Routing

In this example, you can see that I am using method Navigator.push to route to the new screen and Navigator.pop to go back.

Navigator maintains the Stack-based history of routes and whatever is at the top of the stack that is our current Page in our App.

Navigator.push takes two arguments (BuildContext, Route<T>). In the place of Route, we are using MaterialPageRoute which replaces the entire screen with a platform-adaptive transition.

To learn about Transition wait for tomorrow

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: HomePage(),
  ));
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: new Center(
        child: RaisedButton(
          onPressed: () {
            Route route = MaterialPageRoute(builder: (context) => SecondHome());
            Navigator.push(context, route);
          },
          child: Text('Second Home'),
        ),
      ),
    );
  }
}

class SecondHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Hoem'),
      ),
      body: new Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('Go Back'),
        ),
      ),
    );
  }
}

Example 2 : Named Routing

In this example, you can see that I am using method Navigator.pushNamed to route to the new screen and Navigator.pop to go back. Navigator maintain Stack-based history of routes

Navigator.pushNamed takes two required arguments (BuildContext, String,{Object}) and one optional Argument. In the place of String, we are passing the String which we had predefined in routes.

If you have any idea about expressjs then it looks very much familiar to you.

As I told you in earlier that MaterialPageRoute is responsible for page Transition and Here in this complete code I haven’t used this MaterialPageRoute then it may be Little difficult for you change the page transition.

I’ll discuss about onGenerateRoute later in this post that help you . You can have custom Transition along with Named Route.

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    initialRoute: '/',
    routes: <String, WidgetBuilder>{
      '/': (context) => HomePage(),
      '/second': (context) => SecondHome(),
    },
  ));
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: new Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.pushNamed(context, '/second');
          },
          child: Text('Second Home'),
        ),
      ),
    );
  }
}

class SecondHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Home'),
      ),
      body: new Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('Go Back'),
        ),
      ),
    );
  }
}

This was the basic routing and Now I want to tell you something about the above examples.

  1. If in your route / present then it is not mandatory to defined initial route. It will make ‘/’ as your initial route and If you want your initial route different than ‘/’ then you can define.

This below example will run and will open the HomePage

MaterialApp(
  routes: <String, WidgetBuilder>{
    '/': (context) => HomePage(),
    '/second': (context) => SecondHome(),
  },
)
  1. Initial route and home are exactly the same you can use anyone at any place. You just need to take care that if you are initial route then you had defined routes or onGenerateRoute. This is not mandatory that there should be ‘/’ in routes.

This below example will run and will open the second page

MaterialApp(
  home: SecondHome(),
  routes: <String, WidgetBuilder>{
    '/home': (context) => HomePage(),
    '/second': (context) => SecondHome(),
  },
),
  1. If you want that when any route did not match it should show 404 Not Found Link Error Screen then you can use on UnknownRoute.
MaterialApp(
  home: SecondHome(),
  routes: <String, WidgetBuilder>{
    '/home': (context) => HomePage(),
    '/second': (context) => SecondHome(),
  },
  onUnknownRoute: (RouteSettings setting) {
    # To can ask the RouterSettings for unknown router name.
    String unknownRoute = setting.name ;
    return new MaterialPageRoute(
                builder: (context) => NotFoundPage()
    );
  }
),

Example 3 : onGenerateRoute

Here you can see I am using MaterialPageRoute and now you can easily modify the Transition Animation. In this case, you need not to routes onGenerateRoute will create the routes for you. Technically routes are present there but that is not initialized by you.

onGenerateRoute: Creates a route for the given route settings

MaterialApp(
  home: SecondPage(),
  onGenerateRoute: (RouteSettings settings) {
    switch (settings.name) {
      case '/':
        return MaterialPageRoute(builder: (context)=> HomePage());
        break;
      case '/second':
        return MaterialPageRoute(builder: (context)=> SecondPage());
        break;
    }
  },
),

Here is a complete custom Transition of Screen. you can copy and paste in your IDE to see the example. Keep one thing in mind that when you change the page Transition it changes for all OS. Default Transition is Platform dependent.

Full Source Code with Demo


import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: HomePage(),
      onGenerateRoute: (RouteSettings settings) {
        switch (settings.name) {
          case '/':
            return SlideRightRoute(widget:HomePage());
            break;
          case '/second':
            return SlideRightRoute(widget:SecondHome());
            break;
        }
      },
    ),
  );
}
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: new Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.pushNamed(context, '/second');
          },
          child: Text('Second Home'),
        ),
      ),
    );
  }
}
class SecondHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Home'),
      ),
      body: new Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('Go Back'),
        ),
      ),
    );
  }
}

class SlideRightRoute extends PageRouteBuilder {
  final Widget widget;
  AppSlideRightRoute({this.widget})
      : super(
    pageBuilder: (BuildContext context, Animation<double> animation,
        Animation<double> secondaryAnimation) {
      return widget;
    },
    transitionsBuilder: (BuildContext context,
        Animation<double> animation,
        Animation<double> secondaryAnimation,
        Widget child) {
      return new SlideTransition(
        position: new Tween<Offset>(
          begin: const Offset(1.0, 0.0),
          end: Offset.zero,
        ).animate(animation),
        child: child,
      );
    },
  );
}

You can follow me get the get Notified about my activities.

I think I need to write part-2 of this post because there are a lot more to cover.

If you enjoyed or learned let me know on Twitter of anywhere


Top comments (5)

Collapse
 
hsct profile image
HSCT

Can you show me how to add a route to a screen that has @required key?
For examples: I have 2 screens, FirstScreen() and SecondScreen(). The SecondScreen() has 2 @required variables that is passed from the FirstScreen(). How do I define the route to the SecondScreen() in main(){}?

Collapse
 
aliaon profile image
Ali Aon

thanks buddy

Collapse
 
grahamdi profile image
GrahamDi

Hi Nitish,

Please would you publish part 2 on Dev.to. Not all of us can afford to subscribe to Medium and they have blocked Part 2 for me. :-(

Thanks, man.

Collapse
 
nitishk72 profile image
Nitish Kumar Singh

Here is friendly URL : blog.usejournal.com/flutter-advanc...

I will copy and paste the post from medium to dev.to

Collapse
 
grahamdi profile image
GrahamDi

Thanks Nitish, much appreciated. :-)