一篇文章说完Flutter页面路由导航及传参

编程入门 行业动态 更新时间:2024-10-28 03:29:27

一篇文章说完Flutter页面<a href=https://www.elefans.com/category/jswz/34/1771390.html style=路由导航及传参"/>

一篇文章说完Flutter页面路由导航及传参

目录

前言

动态路由

静态路由

静态路由传参

Fluro 实现路由导航与传参


前言

在 Flutter 中,App 多个页面之间的跳转是由 Navigator(导航器)来管理的,如常见的 Navigator.push 跳转到下一页,Navigator.pop 回到上一页,同时也会涉及到页面之间的参数传递。本文主要介绍一下动态路由、静态路由及第三方路由插件 Fluro,它们在页面跳转、参数传递的区别和各自的优缺点,日常开发选择合适的即可。

动态路由

动态路由是不需要显示声明的,通过代码来实现,如下面这样的:

class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(title: "FlutterToDo",theme: ThemeData(brightness: Brightness.dark,),// 直接将 HomePage() 赋值给 MaterialApp 的 homehome: HomePage(),);}
}

页面跳转通过 Navigator.push,在跳转到 SecondPage.dart 页面时,如果有参数时需要通过构造函数将参数传递给 SecondPage.dart,如这里的参数是 pageTitle。

class HomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("FlutterToDo"),),body: Center(child: RaisedButton(child: Text("这是第一个界面,点击进入第二个界面"),onPressed: () {// 点击跳转页面,无参数// Navigator.push// context,//     MaterialPageRoute(//     builder: (context) => SecondPage(),// ));// 带参数的页面跳转Navigator.push(context,MaterialPageRoute(// 参数:pageTitlebuilder: (context) => SecondPage(pageTitle: "SecondPage"),// 调用 then 等待接收 SecondPage 返回的数据)).then((value) => print(value));},                },),),);}
}

SecondPage.dart页面代码,参数 pageTitle依赖接收上个页面传递过来的数据并直接作为当前页面的标题。

import 'package:flutter/material.dart';class SecondPage extends StatelessWidget {final String pageTitle;SecondPage({Key key, this.pageTitle = "第二个界面"});@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text(pageTitle),),body: Center(child: RaisedButton(child: Text("这是第二个界面,点击进入第一个界面"),onPressed: () {// 返回上一个界面,// Navigator.pop(context);// 携带参数上一个界面,"SecondPage pop" 为传递给上一个页面的参数。Navigator.pop(context, "SecondPage pop");},),),);}
}

动态路由简单直接,传参时参数名称定义明确,调用者通过构造函数就能提示具体参数,使用起来比较方便,不用特地的去声明路由,缺点是缺乏统一管理,当前页面需要导入要跳转的页面,页面之间有强依赖,项目后期业务逻辑增多、结构变复杂,维护成本也就增加,不利于业务模块组件化。

静态路由

静态路由又称命名路由,其实现方式是在跳转之前,需要通过在MaterialApp内的routes属性内显式声明路由的名称,代码实现如下:

import 'package:flutter/material.dart';
import 'pages/HomePage.dart';
import 'pages/SecondPage.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(title: "FlutterToDo",// 默认加载的页面initialRoute: '/',// 显式声明路由列表routes: {'/': (context) => HomePage(),'/secondPage': (context) => SecondPage(),},);}
}

此时首页的代码实现及点击按钮的跳转逻辑如下:

// 跳转到第二个界面,
Navigator.pushNamed(context, '/secondPage');

这里的 /secondPage 就是上面 MyApp - > MaterialApp-> routes 中定义的路由,名称必须保持一致。SecondPage 页面点击按钮返回:

// 返回上一个界面
Navigator.pop(context);

静态路由传参

静态路由是通过 MyApp - > MaterialApp-> onGenerateRoute 属性来处理。

import 'package:flutter/material.dart';
void main() => runApp(MyApp());class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(title: "FlutterToDo",initialRoute: '/', // 默认界面// 当页面跳转时进行参数处理onGenerateRoute: (RouteSettings settings) {// ......},);}
}

查看 onGenerateRoute 的源码定义可以看到,根据所给的 route settings 来返回一个 Route<dynamic>

而打开 RouteSettings 类的实现看到其构造函数有 namearguments,其中 name 为路由名称,arguments 就是传递的参数,其类型为 Object

将静态路由的代码优化一下之后:

import 'package:flutter/material.dart';
import 'pages/HomePage.dart';
import 'pages/SecondPage.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {// routes中声明所有的页面final routes = {'/': (context, {arguments}) => HomePage(),'/secondPage': (context, {arguments}) => SecondPage(arguments: arguments),};@overrideWidget build(BuildContext context) {return MaterialApp(title: "FlutterToDo",initialRoute: '/', // 默认界面// 当页面跳转时进行参数处理onGenerateRoute: (RouteSettings settings) {// 1. 根据路由名称从上面声明的 routes 取出类似于 (context, {arguments}) => HomePage()的 pageBuilder函数体var pageBuilder = routes[settings.name];if (pageBuilder != null) {// 2. 判断是否有携带的参数if (settings.arguments != null) {// 创建路由页面并携带参数// 3. 传递 context 和 settings.arguments给 pageBuilder 函数体执行,// 并返回一个Widget页面给到 MaterialPageRoute 的 builderreturn MaterialPageRoute(builder: (context) =>pageBuilder(context, arguments: settings.arguments));} else {// 3. 无参数的情况return MaterialPageRoute(builder: (context) => pageBuilder(context));}}// 默认返回 HomePage页面return MaterialPageRoute(builder: (context) => HomePage());},);}
}

HomePage 点击按钮的跳转和传参:

// 通过arguments指定参数
Navigator.pushNamed(context, "/secondPage", arguments: {'title': "SecondPage title"}).then((value) {// 退出 SecondPage 时返回的参数print(value) // 返回传递数据 SecondPage pop
});

 此时 SecondPage 页面获取参数代码如下:

import 'package:flutter/material.dart';class SecondPage extends StatelessWidget {final Map arguments;SecondPage({Key key, this.arguments});@overrideWidget build(BuildContext context) {String title = arguments != null ? arguments['title'] : "SecondPage";return Scaffold(appBar: AppBar(title: Text(title),),body: Center(child: RaisedButton(child: Text("这是第二个界面,点击进入第一个界面"),onPressed: () {// 返回上一个界面Navigator.pop(context, "返回传递数据 SecondPage pop");},),),);}
}

从上面可以看出,静态路由及传参优点也很明显,声明路由统一在一个位置定义,方便管理,当然也可以创建一个管理类(如:RouteManager)将 routes 中的路由 path 声明为静态的变量。

class RouteManager {static String homePage = "/";static String secondPage = "/secondPage";static routes = {homePage: (context, {arguments}) => HomePage(),secondPage: (context, {arguments}) => SecondPage(arguments: arguments),};
}

此时直接使用 RouteManager.secondPage 就可以了,相比于动态路由,跳转时不再需要导入 SecondPage,页面直接的耦合度降低。缺点通过 arguments 不够直接准确,同时在 SecondPage也需要定义一个 Map 来接收,这里的Map结构就需要调用者和使用者都能明确且准确无误填入参数字段,根据参数字段取出数据,对调用者和使用者都有一定的要求,同时也非常容易出错。

Fluro 实现路由导航与传参

第三方插件 fluro 在 pub地址,接下来,我们通过代码来看看 fluro 是如何解决 动态路由带来的页面耦合度过高和静态路由传参不方便的问题。

在pubspec.yaml中导入插件:

fluro: ^2.0.3

此时 MyApp 代码:

import 'package:flutter/material.dart';class MyApp extends StatelessWidget {MyApp({Key? key}) : super(key: key) {MyRoutes.configureRoutes();}@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter 技术实践',theme: ThemeData(primarySwatch: Colors.blue,),onGenerateRoute: MyRoutes.router.generator,initialRoute: MyRoutes.root,);}
}

MyRoutes 的实现实际上就是封装的 FluroRouter,路由的定义也统一在这个类里面完成,其实现如下: 

import 'package:fluro/fluro.dart';class MyRoutes {static FluroRouter router = FluroRouter();static String testRoutePage = "/testRoutePage";static String secondPage = "/testRoutePage/secondPage";static void configureRoutes() {router.notFoundHandler = Handler(handlerFunc: (BuildContext? context, Map<String, List<String>> params) {return const Text("ROUTE WAS NOT FOUND !!!");});router.define(testRoutePage,handler: Handler(handlerFunc: (_, __) => const TestRoutePage()));router.define(secondPage,handler: Handler(handlerFunc: (_, params) {String title = params['title']?.first ?? "";return SecondPage(title: title,);}));}
}

TestRoutePage 跳转到 SecondPage 并传递 title 参数。

class TestRoutePage extends StatelessWidget {const TestRoutePage({Key? key}) : super(key: key);@overrideWidget build(BuildContext context) {return Scaffold(body: Center(child: RaisedButton(child: const Text("TestRoutePage"),onPressed: () {// 跳转到 SecondPage,传参方式和get请求很像MyRoutes.router.navigateTo(context, MyRoutes.secondPage + "?title=hello").then((value) => print(value));},),),);}
}

SecondPage 页面实现

class SecondPage extends StatelessWidget {String? title;SecondPage({Key? key, this.title = "第二个页面"}) : super(key: key);@overrideWidget build(BuildContext context) {return Scaffold(body: Center(child: RaisedButton(child: Text(title ?? ""),onPressed: () {Navigator.pop(context, "SecondPage pop 参数");},),),);}
}

相比较于动态路由和静态路由,Fluro 传参方式更加简洁,运行在Web上时,而且通用性更高,当然还有更多好用的功能,这里只是简单的介绍 Fluro 的基本使用,详细用法请移步查看 Fluro 相关文档。

小结:日常开发中,路由导航和传参使用频率非常之高,选择合适的路由管理方式不仅有利于项目的维护和扩展,后期如果需要兼容Web等平台时,也能胜任。

本文代码可直接打开 flutter_todo 查看效果,同步更新到同名微信公众号(公众号搜索:flutter_todo)。

更多推荐

一篇文章说完Flutter页面路由导航及传参

本文发布于:2023-06-18 08:58:43,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/768661.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:路由   一篇文章   页面   Flutter

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!