路由 Navigator

如果有同学对 路由 v2 感兴趣的可以去看我的视频, 这里不做讨论 https://www.bilibili.com/video/BV12q4y1d7pv

匿名路由

主要是通过 Push() Pop() 来操作路由,简单场景也能满足业务

img

  • Navigator 路由管理对象

Navigator是一个路由管理的组件,它提供了打开和退出路由页方。

Future push(BuildContext context, Route route) 压入一个新页面到路由堆栈

bool pop(BuildContext context, [ result ]) 压出一个页面出堆栈

  • MaterialPageRoute 定义

MaterialPageRoute继承自PageRoute类,PageRoute类是一个抽象类,表示占有整个屏幕空间的一个模态路由页面,它还定义了路由构建及切换时过渡动画的相关接口及属性。

  MaterialPageRoute({
    // 是一个WidgetBuilder类型的回调函数,它的作用是构建路由页面的具体内容,返回值是一个widget。我们通常要实现此回调,返回新路由的实例。
    WidgetBuilder builder,

    // 包含路由的配置信息,如路由名称、是否初始路由(首页)。
    RouteSettings settings,

    // 默认情况下,当入栈一个新路由时,原来的路由仍然会被保存在内存中,如果想在路由没用的时候释放其所占用的所有资源,可以设置maintainState为 false。
    bool maintainState = true,

    // 表示新的路由页面是否是一个全屏的模态对话框,在 iOS 中,如果fullscreenDialog为true,新页面将会从屏幕底部滑入(而不是水平方向)。
    bool fullscreenDialog = false,
  })
  • 路由传值

传递可以在初始新界面对象时通过构造函数压入

新界面退出后的返回值通过 Navigator.pop 的参数返回

  • 示例

首页 NavPaged

import 'package:flutter/material.dart';

class NavPaged extends StatelessWidget {
  const NavPaged({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('NavPaged'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () async {
            var result = await Navigator.push(
              context,
              MaterialPageRoute(builder: (context) {
                return const DetailPaged(
                  title: "ducafecat",
                );
              }),
            );

            print("路由返回值: $result");
          },
          child: const Text("Navigator.push DetailPage"),
        ),
      ),
    );
  }
}

详情页 DetailPaged

class DetailPaged extends StatelessWidget {
  const DetailPaged({Key? key, this.title}) : super(key: key);

  // 参数
  final String? title;

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('DetailPaged'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 按钮
            OutlinedButton(
              onPressed: () {
                Navigator.pop(context, "ok");
              },
              child: const Text('Back'),
            ),
            // 显示传值
            Text(title ?? ""),
          ],
        ),
      ),
    );
  }
}
image-20220621143123619image-20220621143138030

命名路由

这种方式就优雅了很多,事先定义好路由名字

lib/main.dart

  
  Widget build(BuildContext context) {
    return MaterialApp(
      ...
      routes: {
        '/': (context) => const NavPaged(),
        '/details': (context) => const DetailPaged(),
      },

pushNamed 路由请求, 输入名称即可

onPressed: () async {
  var result = await Navigator.pushNamed(
    context,
    "/details",
    arguments: {'title': "ducafecat"},
  );

  print("路由返回值: $result");
},

取值显示


Widget build(BuildContext context) {
  // 取值
  final arguments = (ModalRoute.of(context)?.settings.arguments ?? <String, dynamic>{}) as Map;
  var title = arguments['title'];

  ...

  // 显示传值
  Text(title ?? ""),

onGenerateRoute 手动解析

上面的命名路由是好,但是 传参数 不灵活,所有采用 onGenerateRoute 来动态处理

  • 定义路由

lib/main.dart

    return MaterialApp(
      ...
      onGenerateRoute: (settings) {
        // Handle '/'
        if (settings.name == '/') {
          return MaterialPageRoute(builder: (context) => const NavPaged());
        }

        // Handle '/details/:id'
        var uri = Uri.parse(settings.name!);
        if (uri.pathSegments.length == 2 &&
            uri.pathSegments.first == 'details') {
          String uid = uri.pathSegments[1];
          return MaterialPageRoute(
            builder: (context) => DetailPaged(
              uid: uid,
            ),
          );
        }

        return MaterialPageRoute(builder: (context) => const UnknownPage());
      },

如果没有命中,返回 UnknownPage 界面

  • 导航页完整代码

lib/pages/nav.dart

import 'package:flutter/material.dart';

class NavPaged extends StatelessWidget {
  const NavPaged({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('NavPaged'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () async {
            var result = await Navigator.pushNamed(
              context,
              "/details/312312312312",
            );

            print("路由返回值: $result");
          },
          child: const Text("Navigator.push DetailPage"),
        ),
      ),
    );
  }
}

class DetailPaged extends StatelessWidget {
  const DetailPaged({Key? key, this.uid}) : super(key: key);

  final String? uid;

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('DetailPaged'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 按钮
            OutlinedButton(
              onPressed: () {
                Navigator.pop(context, "ok");
              },
              child: const Text('Back'),
            ),
            // 显示传值
            Text(uid ?? ""),
          ],
        ),
      ),
    );
  }
}

class UnknownPage extends StatelessWidget {
  const UnknownPage({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Text('UnknownPage'),
    );
  }
}

路由传值

var result = await Navigator.pushNamed( context, "/details/312312312312", );

  • 运行
image-20220621145845023

312312312312 字符串被顺利的传递到了 DetailPage 界面

Last Updated:
Contributors: ducafecat