写点什么

flutter 系列之:Navigator 的高级用法

作者:程序那些事
  • 2023-02-27
    广东
  • 本文字数:2561 字

    阅读完需:约 8 分钟

简介

上篇文章我们讲到了 flutter 中 navigator 的基本用法,我们可以使用它的 push 和 pop 方法来进行 Router 之间的跳转。


在 flutter 中一个 Router 就是一个 widget,但是在 Android 中,一个 Router 就是 Activity,在 IOS 中,一个 Router 是一个 ViewController。


Router 除了之前讲过的 push 和 pop 方法之外,还有一些更加高级的用法,一起来看看吧。

named routes

虽然在 flutter 中 navigator 将 routers 以 stack 的形式进行存储,能做的也只是 push 和 pop 操作,但是事实上 Router 是可以有名字的。


想想也是,如果 Router 没有名字的话,那么如何顺利进行跳转呢?不可能每次都 new 一个 Router 出来吧。


navigator 有一个方法叫做 Navigator.pushNamed()用来将带名字的 Router 压入堆栈,我们来看下它的定义:


  static Future<T?> pushNamed<T extends Object?>(    BuildContext context,    String routeName, {    Object? arguments,  }) {    return Navigator.of(context).pushNamed<T>(routeName, arguments: arguments);  }
复制代码


这个方法需要传入一个 context 和对应的 routeName,同时还可以带一些参数。


那么怎么用这个方法呢?


首先我们需要定义一些 Router,比如说在创建 MaterialApp 的时候可以传入 routes 参数,来设置 named Routers:


MaterialApp(  title: '这是named Routers',  initialRoute: '/firstPage',  routes: {    '/firstPage': (context) => const FirstPage(),    '/secondPage': (context) => const SecondPage(),  },)
复制代码


上面的代码中我们分别定了两个 routers,分别是 firstPage 和 secondPage,他们分别对应一个自定义的 widget。


定义好 Router 之后,我们就可以向下面这样使用了:


onPressed: () {  Navigator.pushNamed(context, '/secondPage');}
复制代码


如果要返回第一个页面的话,那么可以调用 Navigator.pop 方法来实现:


onPressed: () {  Navigator.pop(context);}
复制代码

给 named route 传参数

在上一节我们讲到 pushNamed 的时候,还介绍了它还可以接收参数 arguments。从定义上可以看到 arguments 的类型是 Object 对象,也就是说任何对象都可以作为 named route 的参数。


那么我们先定义一个对象如下:


class TestArguments {  final String name;  final String description;
TestArguments(this.name, this.description);}
复制代码


接下来我们需要创建一个能够接受这个参数的 Routers。


因为所有的 Routers 都是 Widget,所以我们需要创建一个 Widget,并在这个 widget 内部接收传入的参数。


在 flutter 中有两种传递参数的方式,你可以使用 ModalRoute.of(),也可以使用 onGenerateRoute()。


我们先来看下 ModalRoute.of 的定义:


  static ModalRoute<T>? of<T extends Object?>(BuildContext context) {    final _ModalScopeStatus? widget = context.dependOnInheritedWidgetOfExactType<_ModalScopeStatus>();    return widget?.route as ModalRoute<T>?;  }
复制代码


它接收一个 context 参数,然后返回一个 route 对象。


具体的用法如下:


class FirstPage extends StatelessWidget {  const FirstPage({super.key});
static const routeName = '/firstPage';
@override Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments as TestArguments;
return Scaffold( appBar: AppBar( title: Text(args.name), ), body: Center( child: Text(args.description), ), ); }}
复制代码


除了使用 ModalRoute 之外,还可以在 onGenerateRoute()方法中进行参数传递。onGenerateRoute 是在 Route 生成的时候触发的:


MaterialApp(
onGenerateRoute: (settings) { if (settings.name == FirstPage.routeName) { final args = settings.arguments as TestArguments;
return MaterialPageRoute( builder: (context) { return TestArguments( title: args.title, message: args.message, ); }, ); } return null; },)
复制代码


onGenerateRoute 接收一个 settings 对象,我们需要在 settings 对象中设置对应的 name 和 arguments 属性。所以我们需要这样调用:


    Navigator.pushNamed(      context,      FirstPage.routeName,      arguments: TestArguments(        '测试',        '这是一个named Route',      ),    );
复制代码

从 Screen 返回值

有时候我们需要从一个 Screen 返回到之前的 Screen,并且不是简单的返回,我们还希望知道前一个 screen 返回了什么结果,然后可以根据前一个 screen 返回的不同结果来进行不同的处理。


这个时候就需要用到 Navigator.pop 的传参功能了。


比如我们在第一个页面中点击了按钮,跳转到第二个页面:


  final result = await Navigator.push(      context,      MaterialPageRoute(builder: (context) => const SecondScreen()),    );
复制代码


这里我们使用到了 Navigator.push 方法,并且返回了一个 result 的值。


我们可以使用这个值来进行一些逻辑判断。


那么这个 result 的值是哪里传递过来的呢?


没错,就是 SecondScreen 中的 Navigator.pop 方法:


Navigator.pop(context, 'Yes');
复制代码


这里的'Yes'就会传递给 result 供我们进行逻辑判断。

向 Screen 传值

有时候我们需要在页面跳转的过程中传递一些参数,那么怎么才能实现 Screen 之间的参数传递呢?


因为在 flutter 中所有的 Routers 都是 Widget,所以我们可以在跳转到新的页面的时候直接将参数以构造函数的方式传递给 Routers Widget。


比如我们有下面的 Screen Widget:


class NameScreen extends StatelessWidget {
const NameScreen({super.key, required this.name});
final String name;
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('NameScreen'), ),
body: ... ; }}
复制代码


想要传值给它,可以在 onTap 方法中这样写:


onTap: () {        Navigator.push(          context,          MaterialPageRoute(            builder: (context) => NameScreen(name: 'what is your name?'),          ),        );
复制代码

总结

以上就是 Navigator 的更加高级的用法,我们可以通过 Navigator 来进行数据传递等操作,从而实现更加复杂的页面功能。

发布于: 刚刚阅读数: 4
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020-06-07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
flutter系列之:Navigator的高级用法_flutter_程序那些事_InfoQ写作社区