首页 > 其他分享 >Flutter 陈航 21-路由 导航 Route Navigator 页面参数

Flutter 陈航 21-路由 导航 Route Navigator 页面参数

时间:2023-01-07 23:23:22浏览次数:62  
标签:21 title Route 陈航 参数 context Navigator 路由 页面

本文地址


目录

目录

21 | 路由与导航,实现页面切换

如果说 UI 框架的视图元素的基本单位是组件,那应用程序的基本单位就是页面了。对于拥有多个页面的应用程序而言,如何从一个页面平滑地过渡到另一个页面,我们需要有一个统一的机制来管理页面之间的跳转,通常被称为路由管理或导航管理。

我们首先需要知道目标页面对象,在完成目标页面初始化后,用框架提供的方式打开它。比如,在 Android/iOS 中我们通常会初始化一个 Intent 或 ViewController,通过 startActivity 或 pushViewController 来打开一个新的页面;而在 React 中,我们使用 navigation 来管理所有页面,只要知道页面的名称,就可以导航到这个页面。

路由管理

在 Flutter 中,页面之间的跳转是通过 Route 和 Navigator 来管理的:

  • Route 是页面的抽象,主要负责创建对应的界面,接收参数,响应 Navigator 打开和关闭
  • Navigator 会维护一个路由栈管理 Route 的入栈/出栈,还可以直接替换栈内的某一个 Route

根据是否需要提前注册页面标识符,Flutter 中的路由管理可以分为两种方式:

  • 基本路由:无需提前注册,在页面切换时需要自己构造页面实例
  • 命名路由:需要提前注册页面标识符,在页面切换时通过标识符直接打开新的路由

基本路由

在 Flutter 中,基本路由的使用方法和 Android/iOS 打开新页面的方式非常相似:

  • 要导航到一个新页面,需要创建一个 Route,调用 Navigator.push 将新页面压到栈顶
  • 要返回到上一个页面,需要调用 Navigator.pop 方法,将栈顶的页面从堆栈中删除
class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text(widget.title)),
        body: Text(widget.title),
        floatingActionButton: FloatingActionButton(
          onPressed: _onPressed,
          child: Text(widget.title),
        ));
  }

  void _onPressed() {
    if (widget.title == "白乾涛") {
      Route<HomePage> route = MaterialPageRoute(builder: (context) => const HomePage(title: "页面2"));
      Navigator.push(context, route);
    } else {
      Navigator.pop(context);
    }
  }
}

MaterialPageRoute 是一种路由模板,定义了路由创建及切换过渡动画的相关配置,可以针对不同平台,实现与平台页面切换动画风格一致的路由切换动画。

命名路由

基本路由适用于应用中页面不多的场景。在应用中页面比较多的情况下,Flutter 提供了另外一种方式来简化路由管理,即命名路由。我们给页面起一个名字,然后就可以直接通过页面名字打开它了。

路由表 routes

要想通过名字来指定页面切换,我们必须先给应用程序 MaterialApp 提供一个页面名称映射规则,即路由表 routes,这样 Flutter 才知道名字与页面 Widget 的对应关系。

路由表 routes 的类型是 Map<String, WidgetBuilder>

  • key:对应页面名字,定义好后,我们就可以使用 Navigator.pushNamed 来打开页面了
  • value:是一个 WidgetBuilder 回调函数,我们需要在这个函数中创建对应的页面

Flutter 提供了 onUnknownRoute 属性,可以对未知的路由标识符进行统一的页面跳转处理。

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) => MaterialApp(
        home: const HomePage(title: "白乾涛"),
        routes: {
          "first_page": (context) => const HomePage(title: "first_page"),
          "second_page": (context) => const HomePage(title: "second_page"),
        },
        onUnknownRoute: (RouteSettings setting) => MaterialPageRoute(builder: (context) => const UnknownPage()),
      );
}

页面 Page

class HomePage extends StatefulWidget {
  final String title;

  const HomePage({super.key, required this.title});

  @override
  State<HomePage> createState() => HomePageState();
}

class UnknownPage extends StatelessWidget {
  const UnknownPage({super.key});

  @override
  Widget build(BuildContext context) => const Text("UnknownPage,统一的错误路由页");
}
class HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    Object? arguments = ModalRoute.of(context)?.settings.arguments; // 取出参数
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: GestureDetector(
        child: Text("${widget.title}\narguments = $arguments"),
        onTap: () => Navigator.pop(context, "finished from ${widget.title}"), // 页面关闭时传递参数
      ),
      floatingActionButton: FloatingActionButton(onPressed: _onPressed),
    );
  }

  void _onPressed() {
    String routeName = "未知路由";
    if (widget.title == "白乾涛") {
      routeName = "first_page";
    } else if (widget.title == "first_page") {
      routeName = "second_page";
    }
    flog("widget.title = ${widget.title}, routeName = $routeName");
    //Navigator.pushNamed(context, routeName);
    var future = Navigator.pushNamed(context, routeName, arguments: "[from: ${widget.title}]"); // 页面启动时传递参数
    future.then((msg) => flog(msg.toString())); // 设置目标页面关闭时的监听函数
  }
}

页面参数

Flutter 提供了路由参数的机制,可以在打开路由时传递相关参数,在目标页面通过 RouteSettings 获取页面参数。

启动参数

// 传递参数
Navigator.pushNamed(context, routeName, arguments: "[from: ${widget.title}]");
Navigator.of(context).pushNamed(routeName, arguments: "from ${widget.title}");

// 取出参数
Object? arguments = ModalRoute.of(context)?.settings.arguments;

返回参数

与 Android 提供的 startActivityForResult 方法可以监听目标页面的处理结果类似,Flutter 也提供了返回参数的机制。在 push 目标页面时,可以设置目标页面关闭时的监听函数,以获取返回参数;而目标页面可以在关闭路由时传递相关参数。

下面的代码演示了如何获取参数:在 SecondPage 页面关闭时,传递了一个字符串参数,随后在上一页监听函数中,我们取出了这个参数,并将它展示了出来。

// 设置目标页面关闭时的监听函数
Navigator.pushNamed(context, routeName).then((msg) => flog(msg.toString()));

// 页面关闭时传递参数
Navigator.pop(context, "finished from ${widget.title}")

总结

Flutter 提供了基本路由和命名路由两种方式来管理页面间的跳转。其中,基本路由需要自己手动创建页面实例,通过 Navigator.push 完成页面跳转;而命名路由需要提前注册页面标识符和页面创建方法,通过 Navigator.pushNamed 传入标识符实现页面跳转。

Flutter 提供了页面打开与页面关闭的参数机制,我们可以在页面创建和目标页面关闭时,取出相应的参数。

在中大型应用中,我们通常会使用命名路由来管理页面间的切换。命名路由的最重要作用,就是建立了字符串标识符与各个页面之间的映射关系,使得各个页面之间完全解耦,应用内页面的切换只需要通过一个字符串标识符就可以搞定,为后期模块化打好基础。

2023-1-7

标签:21,title,Route,陈航,参数,context,Navigator,路由,页面
From: https://www.cnblogs.com/baiqiantao/p/17033850.html

相关文章

  • 【vue】Vue-router
    Vue-router安装npminstallvue-router--save-devvue-cli中已经选择安装了vue-router,那这里不需要重复安装了解读route路径```src/router/index.js``import......
  • Flutter 陈航 20-通讯 数据传递 Notification EventBus
    本文地址目录目录目录20|跨组件传递数据,只需要记住这三招InheritedWidget父Widget子WidgetWidget树Notification定义通知发送通知监听通知EventBus自定义事件类发......
  • vue-router的使用
    vue-router是vue基础工具的重要组成部分。通过简单的配置路由组件映射关系,可以实现vue页面轻松跳转。 什么是前端路由它是URL地址与组件之间的对应关系,通常使用Hash地......
  • Flutter 陈航 19-手势识别 PointerEvent GestureDetector GestureRecognizer
    本文地址目录目录目录19|用户交互事件该如何响应?指针事件ListenerListener完整代码手势识别GestureDetector拖拽和缩放手势竞技场竞技场默认行为改变竞技场行为Gestu......
  • 第三章 页表(xv6 2021版)
    本文翻译自MTxv6|Chapter3| Pagetables3.1分页硬件3.2内核地址空间3.3代码解析:创建地址空间3.4物理内存分配3.5代码解析:物理内存分配器3.6进程地址空间......
  • 【题解】P4218 [CTSC2010]珠宝商
    这种题出出来有什么必要吗,不就是难写的暴力弱智题。题意给定一棵树和一个文本串\(T\),每个结点上有一个字符,问树上任意路径构成的字符串在\(T\)中的出现次数之和。\(n......
  • vue-router
    vue-router实现页面的跳转在cmd中输入:npminstallvue-router--save-dev如果报错则使用:cnpminstallvue-router--save-dev运行程序(如果报错则降低vue-route......
  • 力扣每日一题2023.1.6---2180. 统计各位数字之和为偶数的整数个数
    给你一个正整数num,请你统计并返回小于或等于num且各位数字之和为偶数的正整数的数目。正整数的各位数字之和是其所有位上的对应数字相加的结果。示例1:输入:num=......
  • 第 321 场周赛
    1.找出中枢整数找出中枢整数SolutionclassSolution{public:intpivotInteger(intn){intsum=(1+n)*n/2;inttmp=(int)sqrt(sum......
  • 计蒜客 - T2144 拼数
    计蒜客-T2144拼数题解:把所有数字看成字符串,但是难道直接降序排就结束了嘛,不是的,我们来看一个反例:31312虽然312>31但是明显31312>31231,所以我们不能简单的排序,我......