Flutter provides a Navigator to realize page hopping. A single page is a route, so it is called route navigation.

There are two ways to jump:

  • To redirect to a Page, pass the Page as a parameter (similar to android’s intent to redirect to an Activity).
  • Jump by named route parameter, which means that PageA is registered in the routing table and given a name, and other pages jump by this name (similar to android implicit jump).

List of Navigator API methods

Direct redirect via route:

  • Push the stack to push a new route
  • PushReplacement Replaces the current route with a new one
  • PushAndRemoveUntil determines how many routes are cleared in the stack according to the parameter and merges a new route into the stack.

Jump through named routes:

  • The pushNamed stack pushes a new route
  • PushReplacementNamed replaces the current route with a new one
  • PushNamedAndRemoveUntil determines how many routes are cleared in the stack according to the parameter, and adds a new route to the stack

Active routing out of stack:

  • Pop Current route out of stack
  • PopAndPushNamed currently routes out of the stack and pushes a new route
  • PopUntil starts at the top of the stack, one pop at a time, until the route specified in the argument
  • CanPop checks whether the current route can be removed from the stack. Returns false if only the current route exists in the stack, and true if there are other routes in front of the current route. That is, the route at the bottom of the stack. This method returns false
  • MaybePop the current route goes out of the stack if it can, and does nothing if it can’t.

Route deletion:

  • removeRoute
  • removeRouteBelow

Route replacement:

  • replace
  • replaceRouteBelow

Route judgment method:

  • Of gets the instance of the Navigator of the current context.
  • Almost all Navigtor method implementations call of followed by a specific method, such as pop:
static bool pop<T extends Object>(BuildContext context, [ T result ]) {
    return Navigator.of(context).pop<T>(result);
  }
Copy the code

Direct redirect through routes

Navigator.push(BuildContext context, Route route)

Description: Jump to a new page without changing current page. That is, pushing a new route onto the stack. Routing relationship:

  • The current routing sequence is A-B-C
  • Push from C D
  • The routing sequence is A-B-C-D
  • If it pops on the D page, the routing order is A-B-C

Passing parameters between pages:

  • Parameters are passed through the constructor of the target page
  • The returned parameters can be received from the target page

Example: page jump, passing parameters to the next page and getting parameters returned to the current page after the next page closes. Current page:

RaisedButton( onPressed: Var result = Navigator. Push (Context, MaterialPageRoute(Builder: (BuildContext Context){return PageA(" This is the argument passed to PageA "); // Pass arguments by constructor})); Result. then((response){this.setState((){text = response[0]; }); }); }, child: Text(" jump to PageA, pass parameters, and receive page return values "),),Copy the code

PageA:

RaisedButton(Child: Text(" return value from PageA "), onPressed: (){navigator.pop (context,[" return parameter from PageA "]); // Navigator. Pop (context," echo parameters from PageA "); // Return a string},)Copy the code
Navigator.pushReplacement(BuildContext context, Route route, { TO result })

Routing relationship:

  • The current routing sequence is A-B-C
  • From C pushReplacement D
  • The routing sequence is A-B-D
  • If pop occurs on the D page, the routing order is A-B

Parameter relation:

  • Parameters are passed through the constructor of the target page
  • The page does not exist and cannot receive the returned parameters from the target page
RaisedButton( onPressed: () is async {/ / receiving a return value of the Future, the return value is an array of var result. = the Navigator pushReplacement (context, MaterialPageRoute (builder: (BuildContext Context){return PageA(" This is the argument passed to PageA "); })); Result. then((response){print("response===$response"); // this.setState((){// text = response[0]; / /}); }); }, child: Text(" the current page is replaced by PageA, can pass parameters, but can not receive the page return value "),Copy the code
Navigator.pushAndRemoveUntil((BuildContext context, Route newRoute, RoutePredicate predicate)

Description: Open a new page and determine how to process routes before the new page based on the value of the predicate. There are three types of predicate cases:

  1. If you pass a method to predicate that returns a value of false, remove all routes before the new page.
  • The current routing sequence is A-B-C-D-E
  • From the E pushAndRemoveUntil page F, and predicate returns false
  • Routing order F, a-E all out of the stack.
  • If it pops on the F page, the app goes back to the desktop.
  1. If predicate passes a method that returns true, the route before the new page remains the same.
  • The current routing sequence is A-B-C-D-E
  • From E pushAndRemoveUntil page F, and the predicate returns true
  • The routing sequence is A-B-C-D-E-F, and a-E remains the same.
  • If pop occurs on the F page, the route is A-B-C-D-E.
  1. If the value of predicate is a named route name specified by modalroute. withName, all routes between the new page and the specified route name are deleted.

Routing relationship:

  • The current routing sequence is A-B-C-D-E
  • From the E pushAndRemoveUntil page F, and the value of predicate is modalroute.withname (‘C’). (There are pits, more on that later)
  • The routing sequence is A-B-C-F, and D and E are out of the stack.
  • If pop occurs on the F page, the routing order is A-B-C.

Parameter relation:

  • Parameters are passed through the constructor of the target page
  • The page does not exist and cannot receive the returned parameters from the target page

Example, passing a method to predicate that returns false or true

RaisedButton( onPressed: () is async {/ / receiving a return value of the Future, the return value is an array of var result. = the Navigator pushAndRemoveUntil (context, MaterialPageRoute (builder: (BuildContext Context) {return PageA(" This is the argument passed to PageA "); }), / / predicate parameters (route) {print (' route = $route} '); // return false; // Delete all routes before PageA return true; // The route before PageA remains the same}); Result. then((response) {// this. SetState ((){// text = response[0]; / /}); }); },Copy the code

Example, passing modalroute. withName to predicate arguments

  1. Suppose there are five routes, T-A-B-C-D
  2. T page push to A, need to set Settings: RouteSettings(name:”pagea”), equivalent to A tag “pagea”, as follows:
Navigator.push(context, MaterialPageRoute(settings: RouteSettings(name:"pagea"),builder: (BuildContext Context) {return PageA(" This is the argument passed to PageA "); }));Copy the code
  1. Then, the routing sequence is A-push-b-push-c, and the routing sequence is T-A-b-C
  2. On the C page pushAndRemoveUntil to the D page, specify modalroute. withName(“pagea”).
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (BuildContext context) {return PageD(" This is the argument passed to PageD "); }), ModalRoute.withName('pagea') );Copy the code
  1. In this case, the routing sequence is T-A-D.
  2. Most importantly Settings: RouteSettings(Name :” Pagea “)

The parameter name in modalroute. withName(name) refers to the name of the registered route and can also be set by the RouteSetting. Therefore, if both the registered route and the RouteSetting are completed, the RouteSetting takes precedence.

Jump through named routes

First, you need to register the route

Register the route in the MaterialApp

class MainPage extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Good'), routes: { "mainpage": (context) => MainPage(), "navigatortest": (context) => NavigatorTest(), "pagea": (context) => PageA("aaa"), "pageb": (context) => PageB("bbb"), "pagec": (context) => PageC("cc"), "paged": (context) => PageD("dd"), }, ); }}Copy the code
Routing hop
  • Navigator.pushNamed(context, “paged”, arguments: “111”); // Jump to paged and pass the argument
  • Navigator.pushReplacementNamed(context, “paged”,arguments: “111”); // Replace the current route with paged and pass the argument
  • Navigator.pushNamedAndRemoveUntil(context, “paged”, (route) { // return true; return false; }, arguments: “111”); // Jumps to the paged route and determines how the routes before the new route will be processed based on the return value of the third predicate parameter. If the predicate parameter is true, the route will remain the same; if the predicate parameter is false, all routes outside the new route will pop.
Navigator.pushNamed(BuildContext context, String routeName, {Object arguments})

Description: Just like the push method, a new page is opened from the current page, and a route is pushed onto the stack. The current route remains unchanged.

Routing relationship:

  • The current routing sequence is A-B-C
  • Push from C D
  • The routing sequence is A-B-C-D
  • If it pops on the D page, the routing order is A-B-C

Parameter transfer:

  • When the pushNamed method is called, there is an optional named argument that is passed to the next page data.
  • The next page gets the parameters in the build method and receives them via modalroute.of (context).settings.arguments.
  • The return value of the pushNamed method is also a Future that receives the data returned by the next page.
RaisedButton( onPressed: () { var result = Navigator.pushNamed(context, "pagea", arguments: "111"); Result.then ((response){// return value of next page}); }, child: Text("pushNamed opens new page, passes parameters and receives return values "),),Copy the code

Var args= modalroute.of (context).settings.arguments;

Class _PageDState extends State<PageD> {@override Widget build(BuildContext context) {// Accepts the var argument args=ModalRoute.of(context).settings.arguments; return Scaffold( appBar: AppBar( title: Text("PageD"), centerTitle: true, ), body: Center(, ); }}Copy the code
Navigator.pushReplacementName()

The Navigator. PushReplacementNamed and Navigator. PushReplacement named after the only difference is to use the registered routing to replace the new PageA direct routing (). The other methods are the same

Navigator.pushNamedAndRemoveUntil()

The Navigator. PushNamedAndRemoveUntil and Navigator. PushAndRemoveUntil named after the only difference is to use the registered routing to replace the new PageA direct routing (). The other methods are the same

Route out of the stack

Navigator.pop(BuildContext context, [ T result ])

Description: Close the current page and pass the parameters to the coming page. That is, the current route is pushed off the stack.

  • The current routing sequence is A-B-C
  • Pop on page C, then route: A-B
  • When pop, you can pass parameters to the current routing page.
RaisedButton(Child: Text(" return value to previous page "), onPressed: (){navigator.pop (context,result); // Any type of argument},)Copy the code
bool canPop(BuildContext context)

Description: Checks whether the current route can be removed from the stack. If only the current route exists in the stack, return false. If there are other routes before the current route, return true. That is, the route at the bottom of the stack. This method returns false.

               if(Navigator.canPop(context)){
                  Navigator.pop(context);
                }
Copy the code

If canPop returns false, but the POP method is executed, an error is reported.

Navigator.maybePop(BuildContext context, [ T result ])

Description: The current route is removed from the stack if it can be removed, but does nothing if it cannot.

  • Is a safe return method for POP.
  • The same parameter applies to pop.
Navigator.maybePop(context);
Copy the code
  • Equivalent to adding a layer of CANPOP judgment to the outer layer of POP, equivalent to:
               if(Navigator.canPop(context)){
                  Navigator.pop(context);
                }
Copy the code
Navigator.popAndPushNamed<T extends Object, TO extends Object>(BuildContext context,String routeName, {TO result,Object arguments,})

Description: The current route is out of the stack, and a new route is pushed onto the stack.

Routing order:

  • The current routing sequence is A-B-C
  • In C popAndPushNamed route D
  • The routing sequence is a-B-D
       RaisedButton(
              onPressed: () {
                Navigator.popAndPushNamed(context, "paged");
              },
              child: Text("popAndPushNamed"),
            ),
Copy the code
Navigator.popUntil(BuildContext context, RoutePredicate predicate)

Description: Routes at the top of the stack are removed one by one until the conditions specified by the predicate. Routing order:

  • The current routing sequence is A-B-C-D-E
  • In E popUntil(context, module.withName (‘B’)), the name within withName can be the name registered for the route or the RouteSetting set up for the route.
  • The routing sequence is a-B
         RaisedButton(
              onPressed: () {
                Navigator.popUntil(context,ModalRoute.withName('pagea'));
              },
              child: Text("popUntil"),
            ),
Copy the code

Route deletion and replacement

Routes are deleted and replaced by existing routes. To delete a route, you need to obtain the reference of the route. Create a Map to store routes that already exist:

class RouteMap { static Map<String,MaterialPageRoute> map = new Map(); Static addRoute(String key,MaterialPageRoute route){map[key]=route; } static MaterialPageRoute getRoute(String key){return map[key]; }}Copy the code

Every time you jump to a new route, a reference to the new route is saved in the RouteMap, as in:

RaisedButton( onPressed: (){ MaterialPageRoute route = MaterialPageRoute(builder: (BuildContext Context) {return PageA(" This is the argument passed to PageA "); }); RouteMap.addRoute("pagea", route); // Save the route Navigator. Push (context,route); }, child: Text("add Route"), ),Copy the code

We assume that the jump order of routes is: A-b-c-d-e-f then the value in RouteMap is:

RouteMap.addRoute("pageb", routeb);
RouteMap.addRoute("pagec", routec);
RouteMap.addRoute("paged", routed);
RouteMap.addRoute("pagee", routee);
RouteMap.addRoute("pagef", routef);
Copy the code
Navigator.removeRoute(BuildContext context, Route route)

Description: Delete a specified route. If the route exists in the stack, delete it. Otherwise, error route order is reported:

  • Assume that the current routing sequence is A-B-C-D-E-F
  • On the page, the Navigator. RemoveRoute (context, RouteMap. GetRoute (” paged “));
  • The routing sequence is a-B-C-E-F
       RaisedButton(
              onPressed: () {
                Navigator.removeRoute(context,RouteMap.getRoute("pagea"));
              },
              child: Text("removeRoute"),
            ),
Copy the code
Navigator.removeRouteBelow(BuildContext context, Route anchorRoute)

Description: Given a route, delete the previous route in the routing table

  • Assume that the current routing sequence is A-B-C-D-E-F
  • On the page, removeRouteBelow (context, RouteMap. GetRoute (” paged “));
  • The routing sequence is a-B-D-E-F
RaisedButton(
              onPressed: () {
                Navigator.removeRouteBelow(context,RouteMap.getRoute("paged"));
              },
              child: Text("removeRouteBelow"),
            ),
Copy the code
Navigator.replace(BuildContext context, { @required Route oldRoute, @required Route newRoute })

Description: Replace an existing route in the routing table with a new route

  • Assume that the current routing sequence is A-B-C-D-E
  • In the E page, replace (context, oldRoute: RouteMap. GetRoute (” pageb “), newRoute: MaterialPageRoute (PageF ());
  • The routing sequence is A-F-C-D-E
         RaisedButton(
              onPressed: () {
                Navigator.replace(context, oldRoute: RouteMap.getRoute("pageb"), newRoute: MaterialPageRoute(builder: (BuildContext context){
                  return PageF("dd");
                }));
              },
              child: Text("replace"),
            ),
Copy the code
Navigator.replaceRouteBelow(BuildContext context, { @required Route anchorRoute, Route newRoute })

Description: Replace the previous route of an existing route in the routing table with a new route

  • Assume that the current routing sequence is A-B-C-D-E
  • In the E page, replace (context, oldRoute: RouteMap. GetRoute (” pagec “), newRoute: MaterialPageRoute (PageF ());
  • The routing sequence is A-F-C-D-E
          RaisedButton(
              onPressed: () {
                Navigator.replaceRouteBelow(context, anchorRoute: RouteMap.getRoute("pagec"),newRoute: MaterialPageRoute(builder: (BuildContext context){
                  return PageF("dd");
                }));
              },
              child: Text("replaceRouteBelow"),
            ),
Copy the code

Similarities and differences between routing navigation and named routing navigation

Route navigation:

  • Jump directly by class name, jump action scattered within each class.
  • Data passing between interfaces must be placed in the constructor of the target class.

Named route:

  • All routes are registered in one place and can be seen at a glance.
  • Data is passed between interfaces through method parameters.
  • If you have to create routes of classes in real time in a business scenario where the data in the constructor is business relevant, then named routes are not appropriate.

Therefore, it is best to choose only one route based on your own practical scenarios. I prefer to use named routes for convenient management.