Routing - now-u/now-u-app GitHub Wiki

What is routing?

Routing is about navigating to different pages on the app.

How do we do it?

When we navigate somewhere we say 2 things, where are we going and what are we taking with us. We do that with the following:

Navigator.of(context).pushNamed('name', arguments: 1);

In flutter, this means go to the named route with the name 'name' and with argument (i.e. what you are taking with you) 1.

Where do these 'named routes' come from?

In the now-u app named routes are all defined in routes.dart. We have a class called routes, which contains all these route strings as follows:

class Routes { static const home = "home"; static const page1 = "page1"; static const page2 = "page2"; }

This is simply used to store the definition of these named routes, so now Routes.home == 'home'. So why do we do this?

  1. This allows us to stop repeatedly using string all over the place (neater and we can change the string and not break the things)
  2. We can now match on this set of routes and it just all very lovely
  3. If we always use Routes. then we won't try to navigate to routes that don't exist

Right so how do we say where we want to navigate now? Same as before just don't use string - use Routes. Navigator.of(context).pushNamed(Routes.home, arguments: 1);

Navigating

Ok great so now we know where we want to go, how do we actually go there?

So in the material app we say onGeneralRoute go use our function defined in routes.dart.

MaterialApp(
  ...
  onGenerateRoute: initRoutes,
  ...
)

The onGeneralRoutes function takes something of type RouteSettings. This contains all that info about where to go and what to take along with loads of other useful things. In the initRoutes function, we can then define what happens when we get different types of info.

The important things to note, for now, in that RouteSettings object are the name and arguments.

The name: Gives the 'where' - so the Routes.somehwere string you gave to Navigation.pushNamed (see above). The arguments: Give the 'what are you taking with you' - so the arguments: you gave to Navigation.pushNamed(Routes.home, arguments: arguments)

Ok so we have the where and the what with what do we do now?

Something like this:

switch (settings.name) {
  case Routes.login:
    {
      return customRoute(builder: (context) => LoginPage(), settings: settings);
    }
}

This is an example of a single case statement in the switch. Firsts thing first, the switch statement is switching on the settings.name (settings is what I've called the object given to the function of type RouteSettings), so this is the 'where are we going' and should have type string (but for us will always be a Routes.something).

So we can then have a case for every possible Route in the Routes class :tada:! This then allows us to define the behavior for every route. In this case if the route is Routes.login (i.e. settings.name == 'login') then we navigate to the login page. (Don't worry about customRoute for now but feel free to check it out, for now just think of that as a MaterialRoute from flutter).

Arguments

Ok great so we are navigating but what about those things we were taking with us - arguments

So as we said before we can now look at settings.arguments to see what arguments we gave during the navigation. Let says the login page neeeds an integer. Well, then we only want to navigate to the login page if we have a integer right? Ok then so lets check:

final args = settings.arguments;

switch (settings.name) {
  case Routes.login:
    {
      if(args is int) {
        return customRoute(builder: (context) => LoginPage(args), settings: settings);
      }
      // Navigate somewhere else
    }
}

And now we can handle arguments as well! So now we can simply do
Navigator.of(context).pushNamed(Routes.login, arguments: 1); And we're off!

Multiple arguments

If you want multiple arguments then make a class. Eg:

class ActionInfoArguments {
  final CampaignAction action;
  final Campaign campaign;

  ActionInfoArguments({
    @required this.action,
    @required this.campaign,
  });
}

Then just check you get something of that type

if (args is ActionInfoArguments) { 
  return customRoute( builder: (context) => ActionInfo( args ), settings: settings);
}