Flutter app页面路由以及路由拦截的实现
作者:岛上码农 发布时间:2023-06-23 14:21:18
为什么要使用路由
在之前我们的代码中,页面跳转使用的代码如下所示:
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => LoginPage()),
);
在开发过程中,随着页面的增加,如果继续使用这种方式会有如下缺陷:
代码耦合严重:涉及到页面跳转的地方就需要插入页面的构造函数,意味着需要知道其他页面的构建方式。
不易维护:一旦某个页面发生了变化,需要将涉及到该页面的跳转全部改变。
权限控制不方便:假设某些页面需要授权后才可以访问,需要在各个地方插入权限判断。
Flutter路由介绍
首先说一下,本篇的路由介绍是 Flutter 1.0的实现方式,Flutter 2.0对路由做了很大的改动,使用了声明式方式重构了路由,使用起来会更为复杂。在 Flutter 的 MaterialApp提供了路由配置参数,当使用路由配置后,MaterialApp 的构造形式如下所示:
return MaterialApp(
//其他参数...
navigatorKey: //全局导航状态Key,
onGenerateRoute: //路由改变响应方法,
initialRoute: //初始化路由路径,
);
navigatorKey是一个GlobalKey<NavigatorState>对象,用于全局存储导航的状态。
onGenerateRoute为一个路由 * ,当路由发生改变时,该方法会被调用,从而可以根据路由参数返回不同的页面,或者进行路由拦截。
initialRoute为初始化路由路径,一般为启动页或首页的路径。
页面结构与逻辑
为了演示路由的使用,我们使用了四个页面:
AppHomePage :首页,与之前的章节的页面框架一样,路由路径为“/”;
Splash:启动页,只有一个图片,实际使用过程可以用于加载引导页,广告或其他用途。页面停留2秒后切换到首页。
LoginPage:登录页,用于演示点击登录按钮通过路由切换到登录页。
NotFound:即404页面,当路由表中没有匹配的路径时,跳转到404页面。
这里的路由跳转分为了两种,一是从启动页跳转到首页,这种跳转不可返回的;二是正常的调整,可以点击返回按钮返回到上一级。在 Flutter 中提供不同的方法应对这两种情况。
实现关键代码
首先是路由表和路由拦截响应的实现,在 routers文件夹新建 router_table.dart 文件,代码如下:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../app.dart';
import '../login.dart';
import '../not_found.dart';
import '../splash.dart';
class RouterTable {
static String splashPath = 'splash';
static String loginPath = 'login';
static String homePath = '/';
static String notFoundPath = '404';
static Map<String, WidgetBuilder> routeTables = {
//404页面
notFoundPath: (context) => NotFound(),
//启动页
splashPath: (context) => Splash(),
//登录
loginPath: (context) => LoginPage(),
//首页
homePath: (context) => AppHomePage(),
};
///路由拦截
static Route onGenerateRoute<T extends Object>(RouteSettings settings) {
return CupertinoPageRoute<T>(
settings: settings,
builder: (context) {
String name = settings.name;
if (routeTables[name] == null) {
name = notFoundPath;
}
Widget widget = routeTables[name](context);
return widget;
},
);
}
}
这里全部使用了静态属性和静态方法,是为了可以直接从过类名访问属性和方法,而无需反复构建对象。这样,路由访问的时候也可以通过类名的静态属性直接访问,可以避免拼写错误。有了这个类了后,App 的所有页面都可以通过这个类集中管理,从而避免多处维护了。
这里关键的是onGenerateRoute方法,该方法接收了一个 RouteSettings 对象,该对象会有个 name 属性包含路由路径名称,同时还有个 arguments 用于携带路由参数。可以通过这个属性来与路由表的页面进行匹配。若匹配到则返回相应的页面;若没有匹配到,则路由到404页面。同时,若需要做权限控制,也可以在这里拦截,比如定位到403页面或直接提醒无访问权限。
接下来就是改造 main.dart 文件,在构建 MaterialApp 时使用对应的理由配置:
import 'package:flutter/material.dart';
import 'routers/router_table.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final GlobalKey navigationKey = GlobalKey<NavigatorState>();
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigationKey,
onGenerateRoute: RouterTable.onGenerateRoute,
initialRoute: RouterTable.splashPath,
);
}
}
这里会发现在 main.dart中我们无需再通过 import引入相关的页面 了,而是直接配置路由的配置属性即可。
页面路由跳转
页面路由跳转更为简便,在 Flutter 中的 NavigatorState 中分别提供了 pushNamed 方法和pushReplacementNamed 方法,前者会在导航栏有返回按钮,后者是使用路由后的页面直接替换当前页面,适用于启动页的调整。 在启动页中未来停留几秒,使用了一个定时器,在2秒后再进行跳转,实际可以用于做一些预加载资源的提示或者广告展示。
@override
void didChangeDependencies() {
super.didChangeDependencies();
if (!_initialized) {
_initialized = true;
Timer(const Duration(milliseconds: 2000), () {
Navigator.of(context).pushReplacementNamed(RouterTable.homePath);
});
}
}
普通页面的跳转直接使用 pushNamed 即可,若要返回上一级,则使用 pop 方法。push 和 pop方法均可以携带参数,下一篇我们再来介绍如何处理路由参数。这里我们特意加了一个错误的路由演示404跳转:
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ButtonUtil.primaryTextButton('登录', () {
Navigator.of(context).pushNamed(RouterTable.loginPath);
}, context),
SizedBox(
height: 10,
),
ButtonUtil.primaryTextButton('404', () {
Navigator.of(context).pushNamed('errorRoute');
}, context),
],
),
),
最终运行效果如下图所示。
来源:https://juejin.cn/post/6972894245321441294
![](https://www.aspxhome.com/images/zang.png)
![](https://www.aspxhome.com/images/jiucuo.png)
猜你喜欢
- 关于迭代器你都知道什么?什么是迭代器?  所谓迭代的意思就是交换替代,迭代器并不是一种数据结构或者集合,
- 此方案适用于解决springboot项目运行时动态添加数据源,非静态切换多数据源!!!一、多数据源应用场景:1.配置文件配置多数据源,如默认
- 现在越来越多手机支持OTG功能,通过OTG可以实现与外接入的U盘等USB设备实现数据传输。 USB OTG(On The Go)作
- float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用 java.math.BigDecimal。而且使用BigDe
- 本文实例为大家分享了java实现图书馆管理系统的具体代码,供大家参考,具体内容如下思路:所有包都在book_manage包里利用面向对象的多
- Condition的作用是对锁进行更精确的控制。Condition中的await()方法相当于Object的wait()方法,Conditi
- 下面是我做C#第一个项目的过程:1.首先打开VS,这里我用的是VS2022预览版,鼠标双击打开VS;图一2.打开VS后会出现下面的页面,鼠标
- 文章来源:互联网 作者:skywoo/CSDNWindows2000+Apache2.0.48+resin2.1.6 &nbs
- using System.Runtime.InteropServices; using System.Text; publicclass F
- 缘起工作时使用java开发服务器后台,用Jersey写Restful接口,发现有一个Post方法始终获取不到参数,查了半天,发现时获取参数的
- 本文实例讲述了C#实现鼠标移动到曲线图上显示值的方法。分享给大家供大家参考。具体实现方法如下:一、问题:完成折线图报表后,产品经理要求把折线
- 本文实例为大家分享了java实现通讯录管理系统的具体代码,供大家参考,具体内容如下完成项目的流程:1.根据需求,确定大体方向 2.功能模块分
- 概述Selenium是一款免费的分布式的自动化测试工具,支持多种开发语言,无论是C、 java、ruby、python、或是C# ,你都可以
- 本文实例讲述了基于.net实现裁剪网站上传图片的方法。由于客户端Javascript不能操作文件,所以只能先上传图片再在服务器端剪切。1、上
- 前言:经常会看到有一些app的banner界面可以实现循环播放多个广告图片和手动滑动循环。本以为单纯的ViewPager就可以实
- 如图所示为程序效果动画图地图滚动的原理在本人之前博客的文章中介绍过人物在屏幕中的移动方式,因为之前拼的游戏地图是完全填充整个手机屏幕的,所以
- 本文实例讲述了Android TextView实现带链接文字事件监听的三种常用方式。分享给大家供大家参考,具体如下:/** * TextVi
- 本文实例讲述了java线程同步操作。分享给大家供大家参考,具体如下:java线程同步public class Hello { p
- 该功能本来可以通过拉动水平和垂直滚动条来实现,但实际使用中,用户更趋向于直接用鼠标拖动页面来实现,很多看图类软件都有这种类似的功能。而.ne
- 前言大家都知道在Java中,除了8种基本数据类型外,其他的都是引用类型。使用引用类型是为了更好地贯彻面向对象的思想,那为什么还要保留8种基本