There are two ways of Flutter route jump: one is to use the system native jump method. The second is to use a third-party framework…

The original route

According to the official documentation, we usually use “screens” to refer to different pages (interfaces) of an application. For example, an app has a “screen” that displays a list of products, and when a user clicks on an image of an item, it jumps to a new “screen” that displays detailed information about the item.

Terminology: In Flutter, screens and pages are both called routes, collectively referred to as “route” in this article.

In Android development, an Activity is “routing”; in iOS development, a ViewController is “routing.” In Flutter, “routing” is also a Widget. How do I jump from a route to a new route?

MaterialPageRoute

The MaterialPageRoute is derived from the PageRoute class, which is an abstract class that represents a modal routing page occupying the entire screen space. It also defines the interface and properties of the transition animation during route construction and switching. MaterialPageRoute is a component provided by the Material component library, which can realize the route switching animation consistent with the style of platform page switching animation for different platforms:

  • For Android, when a new page is opened, the new page slides from the bottom of the screen to the top of the screen; When you close a page, the current page slides from the top of the screen to the bottom of the screen and disappears, while the previous page is displayed.
  • For iOS, when a page is opened, a new page slides from the right edge of the screen to the left until the new page is fully displayed, while the previous page slides from the current screen to the left and disappears. When you close a page, the reverse happens: the current page slides out from the right side of the screen, while the previous page slides in from the left.
  MaterialPageRoute({
    WidgetBuilder builder,
    RouteSettings settings,
    bool maintainState = true.bool fullscreenDialog = false,})Copy the code
  • builderWidgetBuilder is a callback function of type WidgetBuilder that builds the details of the routing page and returns a widget. We typically implement this callback to return an instance of the new route.
  • settingsContains route configuration information, such as route name and initial route (home page).
  • maintainState: By default, when a new route is pushed, the original route is still stored in memory. If you want to release all resources occupied by the route when it is not used, you can set this parametermaintainState To false.
  • fullscreenDialogIndicates whether the new routing page is a full-screen modal dialog box in iOS, iffullscreenDialogtrueThe new page will slide in from the bottom of the screen (instead of horizontally).

Navigator

Navigator is a routing management component that provides methods to open and exit the routing page. The Navigator manages a collection of active routes through a stack. The current page is usually the route to the top of the stack. Navigator provides a number of methods to manage the routing stack, and we’ll cover just two of its most common methods:

Future push(BuildContext context, Route route)

When the given route is pushed onto the stack (that is, a new page is opened), the return value is a Future object to receive the data returned when the new route is pushed off the stack (that is, closed).

bool pop(BuildContext context, [ result ])

The top of the stack is routed off the stack, and result is the data returned to the previous page when the page is closed.

There are many other methods for Navigator, such as navigator.replace, navigator.popuntil, etc. Please refer to the API documentation or SDK source notes for details. Next, we will introduce another routing concept, named routing.

Instance methods

Any static method in a Navigator class that takes context as the first argument corresponds to a Navigator instance method, For example, Navigator. Push (BuildContext context, Route Route) is equivalent to Navigator. Of (context).push(Route Route).

Navigate to a new page and back

  1. Create two routes

    First, let’s create two routes. This is the simplest example, each route contains only one button. Click the button on the first route to switch to the second route, and click the button on the second route to switch back to the first route.

    class FirstRoute extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('First Route'),
          ),
          body: Center(
            child: RaisedButton(
              child: Text('Open route'),
              onPressed: () {
                // Navigate to second route when tapped.},),),); }}class SecondRoute extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("Second Route"),
          ),
          body: Center(
            child: RaisedButton(
              onPressed: () {
                // Navigate back to first route when tapped.
              },
              child: Text('Go back! '),),),); }}Copy the code
  2. Jump to the second route with navigator.push ()

    Jump to the new Route using the navigator.push () method, which adds a Route object to the Navigator stack. So where does this Route object come from? You can implement one yourself, or use the MaterialPageRoute class directly. It is very convenient to use MaterialPageRoute, and the framework already provides us with a switch animation similar to the platform native.

    In the build() method of the FirstRoute widget, modify the onPressed() callback:

    // Within the 'FirstRoute' widget
    onPressed: () {
      Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => SecondRoute()),
      );
    }
    Copy the code
  3. Use navigator.pop () to fall back to the first route

    How do I close the second route and roll back to the first? Using the navigator.pop () method, the pop() method removes the Route object from the Navigator stack.

    The onPressed() callback on the SecondRoute widget returns the first route:

    // Locate the SecondRoute widget Within the SecondRoute widget
    onPressed: () {
      Navigator.pop(context);
    }
    Copy the code

Pass the data to the new page

In the development process, we often need to be able to transfer some data when jumping to a new page. For example, passing information about the element the user clicked on.

  1. Passed model data classes

    class Todo {
      final String title;
      final String description;
    
      Todo(this.title, this.description);
    }
    Copy the code
  2. Jump to the new page displayed

    The data is received by defining the variable Todo

    class DetailScreen extends StatelessWidget {
      // Declare a member variable to hold the Todo object
      final Todo todo;
    
      // The constructor needs Todo objects
      DetailScreen({Key key, @required this.todo}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        // Use Todo objects to build UI
        return Scaffold(
          appBar: AppBar(
            title: Text(todo.title),
          ),
          body: Padding(
            padding: EdgeInsets.all(16.0), child: Text(todo.description), ), ); }}Copy the code
  3. The original page

    Navigator. Push jumps to the new page and passes in the Todo model.

    void main() {
      runApp(MaterialApp(
        title: 'Passing Data',
        home: TodosScreen(
          todos: List.generate(
            20,
            (i) => Todo(
              'Todo $i'.'A description of what needs to be done for Todo $i'(), ((), ((), ((); }class TodosScreen extends StatelessWidget {
      final List<Todo> todos;
    
      TodosScreen({Key key, @required this.todos}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Todos'),
          ),
          body: ListView.builder(
            itemCount: todos.length,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text(todos[index].title),
                onTap: () {
         					// When the user clicks on the list, navigate to the DetailScreen and pass the current TOdo model to itNavigator.push( context, MaterialPageRoute( builder: (context) => DetailScreen(todo: todos[index]), ), ); }); },),); }}Copy the code

Or pass parameters using RouteSettings

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

class Todo {
  final String title;
  final String description;

  Todo(this.title, this.description);
}

void main() {
  runApp(MaterialApp(
    title: 'Passing Data',
    home: TodosScreen(
      todos: List.generate(
        20,
        (i) => Todo(
          'Todo $i'.'A description of what needs to be done for Todo $i'(), ((), ((), ((); }class TodosScreen extends StatelessWidget {
  final List<Todo> todos;

  TodosScreen({Key key, @required this.todos}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Todos'),
      ),
      body: ListView.builder(
        itemCount: todos.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(todos[index].title),
            onTap: () {
              // When the user clicks on the list, navigate to the DetailScreen and pass the current TOdo model to it
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => DetailScreen(),
                  // Pass parameters as part of the route. The DetailScreen reads the parameters from these Settings.settings: RouteSettings( arguments: todos[index], ), ), ); }); },),); }}class DetailScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Get routing parameters
    final Todo todo = ModalRoute.of(context).settings.arguments;

    return Scaffold(
      appBar: AppBar(
        title: Text(todo.title),
      ),
      body: Padding(
        padding: EdgeInsets.all(16.0), child: Text(todo.description),se ), ); }}Copy the code

Returns data from a page

In some cases, we need to return some data when we go back to the previous screen. For example, when we jump to a new screen, there are two options for the user to choose. When the user clicks an option, the user will be returned to the first screen, and the information of the user’s choice can be known on the first screen. You can do this using navigator.pop ().

The First page

When navigator. push jumps, the returned data is received with await and UI updates can be made with setState

import 'package:defensor/views/home/second.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class First extends StatefulWidget {
  First({Key key}) : super(key: key);

  @override
  _FirstState createState() => _FirstState();
}

class _FirstState extends State<First> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First'),
      ),
      body: Container(
        child: Center(
            child: CupertinoButton(
                child: Text('jump'),
                onPressed: () async {
                    var restult = await Navigator.push(context, MaterialPageRoute(builder: (context) => Second()));
                    // Restult is returned data
                    print(restult); })),),); }}Copy the code

The Second page

Use navigator.pop (context, data) to return the data in the second argument.

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class Second extends StatefulWidget {
  Second({Key key}) : super(key: key);

  @override
  _SecondState createState() => _SecondState();
}

class _SecondState extends State<Second> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second'),
      ),
      body: Container(
        child: Center(
            child: CupertinoButton(
                child: Text('Return and transfer data'),
                onPressed: () {
                      / / data back
                      var data = 'I'm the data that comes back.'; Navigator.pop(context, data); })),),); }}Copy the code

Navigate to the routes table with the corresponding name

In the Navigation to a new page and Back section, we learned how to navigate to a new interface (Screen) by creating a new route and pushing it into the Navigator class.

However, this can lead to code duplication if we need to navigate to the same interface in many parts of the application. In this case, it is very convenient to define a named route and use it for navigation.

To use named routes, we can use the navigator.pushnamed () method. The following example shows how to use named routing to implement the functionality in the previous section.

Create two interfaces

class FirstScreen extends StatelessWidget {
  /// Routing,
  static const routeName = '/';
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Screen'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('Launch screen'),
          onPressed: () {
            // Navigate to the second screen when tapped.},),),); }}class SecondScreen extends StatelessWidget {
  /// Routing,
  static const routeName = '/second';
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Second Screen"),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () {
            // Navigate back to first screen when tapped.
          },
          child: Text('Go back! '),),),); }}Copy the code

Define the routing

We need to define our route with additional attributes initialRoute and Routes for the MaterialApp constructor

The initialRoute attribute defines the route from which the application should be started. The Routes attribute defines all the available named routes and the widgets we should build when we jump to them.

MaterialApp(
  // Start the application by naming the path with a slash
  // In this case, the application will start from the FirstScreen Widget
  initialRoute: '/',
  routes: {
    // When we jump to "/", build the FirstScreen Widget
    FirstScreen.routeName: (context) => FirstScreen(),
    // When we jump to "/second", build the SecondScreen Widget
    SecondScreen.routeName: (context) => SecondScreen(),
  },
);
Copy the code

Please note that

When using initialRoute, you need to make sure that you do not also define the home attribute.

Jump to the second screen

With Widgets and routes in place, we are ready to jump to the page. Here, we’ll use the navigator.pushnamed () function. This tells Flutter to build the widget we defined in the Routes table and launch the interface.

In the build() method of the FirstScreen Widget, we will update the onPressed() callback:

// In 'FirstScreen' Widget
onPressed: () {
  // Use the named route to jump to the second interface
  Navigator.pushNamed(context, SecondScreen.routeName);
}
Copy the code

Return to the first screen

To jump back to the first page, we can use the navigator.pop () method.

// In SecondScreen Widget
onPressed: () {
  // Pop the current route from the stack
  // to return to the first screen
  Navigator.pop(context);
}
Copy the code

The resources:

Flutter official Chinese Website (flutter.cn/docs/get-st…)

Flutter of actual combat (book. Flutterchina. Club /)