Flutter导航:Navigator&router

路由(Route)在移动开发中通常指页面。路由管理,就是管理页面之间如何跳转,通常也可被称为导航管理。在Flutter中,不同页面之间进行切换和发送数据,这些页面被称为Route(路由),是由一个Navigator的widget进行管理。Flutter中的路由管理和原生开发类似,导航管理都会维护一个栈,入栈(push)操作对应打开一个新页面,出栈(pop)操作对应页面关闭操作,而路由管理主要是指如何来管理路由栈。

Navigator

常用方法

  • push 将设置的router信息推送到Navigator上,实现页面跳转。
  • of 主要是获取 Navigator最近实例的好状态。
  • pop 返回到上个页面。
关闭两个页面后跳转到 settings 页面
Navigator.of(context)
  ..pop()
  ..pop()
  ..pushNamed('/settings');
  • canPop 判断是否可以导航到新页面
  • maybePop 可以理解为canPop的升级版,maybePop则对此进行了升级——如果可以pop则直接pop,否则什么都不做。
  • popAndPushNamed 指将当前页面pop,然后跳转到制定页面
  • popUntil 反复执行pop ,直到返回到我们指定的页面为止
  • pushAndRemoveUntil 跳转到新的页面,并删除先前的所有路由,常用于退出登录后返回登录页面,这时候关闭登录页面就直接退出App。
  • pushNamedAndRemoveUntil 同上,不过这里是使用命名路由
  • pushReplacement 路由替换。
  • pushReplacementNamed 同上,不过这里是使用命名路由
  • removeRoute 从Navigator中删除路由,同时执行Route.dispose操作。
  • removeRouteBelow 从Navigator中删除路由,同时执行Route.dispose操作,要替换的路由是传入参数anchorRouter里面的路由。
  • replace 将Navigator中的路由替换成一个新路由。
  • replaceRouteBelow 将Navigator中的路由替换成一个新路由,要替换的路由是是传入参数anchorRouter里面的路由。

**

flutter中的默认导航分成两种,一种是命名的路由,一种是构建路由。

**

构建路由

直接调用Navigator的构建方法进行界面跳转的方式叫构建路由

Push到下一个界面(不带参数),并接收返回数据

Navigator.push 的返回值为Future, 所以可以用then接收数据

import 'package:flutter/material.dart';
import 'package:exercise/secondPage.dart';

void main() => runApp(new MaterialApp(home: new MyApp()));

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('首页'),
      ),
      body: new Center(
        child: new RaisedButton(
          onPressed: () {
            //界面跳转方法push
            Navigator.push<String>(context,
                new MaterialPageRoute(builder: (BuildContext context) {
               return new SecondPage();
            })).then((String result) {
              //接收并打印返回界面的参数
              print(result);
            });
          },
          child: Text('跳转'),
        ),
      ),
      //bottomNavigationBar: new BottomNavigationWidget(),
    );
  }
}

Pop回上一个界面并返回参数

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('SecondPage'),
      ),
      body: SafeArea(
          child: RaisedButton(
              child: Text("返回"),
              onPressed: () {
                //退出当前页面,并返回参数
                Navigator.pop(context, "我胡汉三回来了");
              })),
    );
  }
}

push下个界面(带参数)

import 'package:flutter/material.dart';
import 'package:exercise/secondPage.dart';

void main() => runApp(new MaterialApp(home: new MyApp()));

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('首页'),
      ),
      body: new Center(
        child: new RaisedButton(
          onPressed: () {
            //界面跳转
            Navigator.push<String>(context,
                new MaterialPageRoute(builder: (BuildContext context) {
              return new SecondPage(s: '子界面');
            })).then((String result) {
              //接收并打印返回界面的参数
              print(result);
            });
          },
          child: Text('跳转'),
        ),
      ),
    );
  }
}

第二个界面

import 'package:flutter/material.dart';

class SecondPage extends StatelessWidget {
  final s;
//  SecondPage(this.s);
  SecondPage({Key key, @required this.s}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("$s"),
      ),
      body: SafeArea(
          child: RaisedButton(
              child: Text("返回"),
              onPressed: () {
                //退出当前页面,并返回参数
                Navigator.pop(context, "我胡汉三回来了");
              })),
    );
  }
}

命名路由

将应用中需要访问的每个页面命名为不重复的字符串,通过这些字符串来导航到具体页面的方式叫命名路由。一般在app中使用的都是命名路由方式,进行路由管理。

简单使用

import 'package:flutter/material.dart';
import 'package:exercise/secondPage.dart';

void main() => runApp(new MaterialApp(
      home: new MyApp(),
      ///注册路由
      routes: {
        ///SecondPage界面的路由地址
        'second_page': (context) => SecondPage(s: '路由界面'),
      },
    ));

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('首页'),
      ),
      body: new Center(
        child: new RaisedButton(
          onPressed: () {
            //界面跳转
            Navigator.pushNamed(context, 'second_page');
          },
          child: Text('跳转'),
        ),
      ),
      //bottomNavigationBar: new BottomNavigationWidget(),
    );
  }
}

SecondPage类 内容同上!

界面跳转传参

import 'package:flutter/material.dart';
import 'package:exercise/secondPage.dart';

void main() => runApp(new MaterialApp(
      home: new MyApp(),
      ///注册路由
      routes: {
        ///SecondPage界面的路由地址
        'second_page': (context) => SecondPage(s: '路由界面'),
      },
    ));

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('首页'),
      ),
      body: new Center(
        child: new RaisedButton(
          onPressed: () {
            //界面跳转
            Navigator.of(context)
                .pushNamed('second_page', arguments: '传参数界面')
                .then((msg) {//接收下级界面返回参数
              print(msg);
            });
          },
          child: Text('跳转'),
        ),
      ),
    );
  }
}

//SecondPage界面
import 'package:flutter/material.dart';

class SecondPage extends StatelessWidget {
  final s;
  SecondPage({Key key, @required this.s}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    //取出路由参数
    String msg = ModalRoute.of(context).settings.arguments as String;
    return Scaffold(
      appBar: AppBar(
        title: Text("$s"),
      ),
      body: SafeArea(
          child: RaisedButton(
              child: Text('$msg'),
              onPressed: () {
                //退出当前页面,并返回参数
                Navigator.pop(context, "我胡汉三回来了");
              })),
    );
  }
}

命名路由封装

创建路由管理类(app_routes.dart)

import 'package:flutter/material.dart';
import 'package:exercise/secondPage.dart';
import 'package:exercise/threePage.dart';

final String secondPage = '/SecondPage';
final String threePage = '/ThreePage';

// 配置路由表
final routes = {
  secondPage: (context) => SecondPage(),
  threePage: (context) => ThreePage(),
};

class UnknownPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('跳转错误'),
        centerTitle: true,
      ),
    );
  }
}

// 路由拦截(固定写法)
Route onGenerateRoute(RouteSettings settings) {
  final String name = settings.name;
  final Function pageBuilder = routes[name];
  if (pageBuilder != null) {
    if (settings.arguments != null) {
      // 如果透传了参数
      return MaterialPageRoute(
          builder: (context) =>
              pageBuilder(context, arguments: settings.arguments));
    } else {
      // 没有透传参数
      return MaterialPageRoute(builder: (context) => pageBuilder(context));
    }
  }
  return MaterialPageRoute(builder: (context) => UnknownPage());
}
//首先从路由表中拿到路由的 builder,如果能够拿到 builder,则判断是否存在 RouteSettings,如果存在则直接通关构造函数的 arguments 传递给页面 Page Widget。
//这种条件就允许页面 Widget 构造函数中,必须有 arguments 这个参数才可以,比如 /sign 代码如下:
//这样的优点在于不需要通过 ModalRoute.of(context).settings.xxx 拿数据。直接映射到 Widget 中

初始化路由并跳转子界面,不传参数(main.dart)

import 'package:flutter/material.dart';
import 'package:exercise/app_routes.dart';

void main() => runApp(
      new MaterialApp(
        home: new MyApp(),
        //注册路由
        routes: routes,
        onGenerateRoute: onGenerateRoute,
        //路由错误页面
        onUnknownRoute: (RouteSettings setting) =>
            MaterialPageRoute(builder: (context) => UnknownPage()),
      ),
    );

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('首页'),
      ),
      body: new Center(
        child: new RaisedButton(
          onPressed: () {
            //界面跳转( 无参数)
            Navigator.pushNamed(context, secondPage).then((msg) {
              print(msg);
            });
          },
          child: Text('跳转'),
        ),
      ),
      //bottomNavigationBar: new BottomNavigationWidget(),
    );
  }
}

初始化路由并跳转子界面,传参数并返回值给父试图(secondPage.dart)

import 'package:flutter/material.dart';
import 'package:exercise/app_routes.dart' as mRoutes;

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("按钮"),
      ),
      body: SafeArea(
          child: Column(
        children: <Widget>[
          new RaisedButton(
              child: Text('返回'),
              onPressed: () {
                //退出当前页面,并返回参数
                Navigator.pop(context, "我胡汉三回来了");
              }),
          new RaisedButton(
              child: Text('下一个界面'),
              onPressed: () {
                //跳转子界面,传值参数
                Navigator.pushNamed(context, mRoutes.threePage,
                    arguments: '我是谁');
              })
        ],
      )),
    );
  }
}

接收父界面传递参数(threePage.dart)

import 'package:flutter/material.dart';

class ThreePage extends StatelessWidget {
  //final s;
  //ThreePage({Key key, @required this.s}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    //取出父界面路由参数
    String msg = ModalRoute.of(context).settings.arguments as String;
    return Scaffold(
      appBar: AppBar(
        title: Text('界面三'),
      ),
      body: SafeArea(
          child: RaisedButton(
              child: Text('$msg'),
              onPressed: () {
                //退出当前页面,并返回参数
                Navigator.pop(context);
              })),
    );
  }
}

遇到的坑

在这里插入图片描述
解决方式
在这里插入图片描述

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页