写点什么

Flutter 路由及路由拦截跳转 404

作者:岛上码农
  • 2022 年 3 月 29 日
  • 本文字数:2538 字

    阅读完需:约 8 分钟

Flutter 路由及路由拦截跳转404

为什么要使用路由

在之前我们的代码中,页面跳转使用的代码如下所示:


 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 秒后再进行跳转,实际可以用于做一些预加载资源的提示或者广告展示。


@overridevoid didChangeDependencies() {  super.didChangeDependencies();  if (!_initialized) {    _initialized = true;    Timer(const Duration(milliseconds: 2000), () {      Navigator.of(context).pushReplacementNamed(RouterTable.homePath);    });  }}
复制代码


普通页面的跳转直接使用 pushNamed 即可,若要返回上一级,则使用 pop 方法。pushpop方法均可以携带参数,下一篇我们再来介绍如何处理路由参数。这里我们特意加了一个错误的路由演示 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),    ],  ),),
复制代码


最终运行效果如下图所示。




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

岛上码农

关注

用代码连接孤岛,公众号@岛上码农 2022.03.03 加入

从南漂到北,从北漂到南的业余码农

评论

发布
暂无评论
Flutter 路由及路由拦截跳转404_flutter_岛上码农_InfoQ写作平台