Flutter App页面路由及路由拦截实现

简介: 直接使用页面跳转会带来诸多缺陷,通过路由管理可以降低页面耦合,提高代码的可维护性和权限控制。本篇介绍了 Flutter 的路由管理和拦截实现。

为什么要使用路由

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

 Navigator.of(context).push(
  MaterialPageRoute(builder: (context) => LoginPage()),
);

在开发过程中,随着页面的增加,如果继续使用这种方式会有如下缺陷:

  • 代码耦合严重:涉及到页面跳转的地方就需要插入页面的构造函数,意味着需要知道其他页面的构建方式。
  • 不易维护:一旦某个页面发生了变化,需要将涉及到该页面的跳转全部改变。
  • 权限控制不方便:假设某些页面需要授权后才可以访问,需要在各个地方插入权限判断。

Flutter路由介绍

首先说一下,本篇的路由介绍是 Flutter 1.0的实现方式(在1.0,2.0到3.0版本都可以用),Flutter 2.0对路由做了很大的改动,使用了声明式方式重构了路由,使用起来会更为复杂,主要是应对 Web 端设计的。在 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 方法。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),
    ],
  ),
),

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

路由及拦截.gif


欢迎关注个人公众号:岛上码农

相关文章
|
3月前
|
安全 Java 应用服务中间件
【Azure 应用服务】App Service 默认页面暴露Tomcat版本信息,存在安全风险
【Azure 应用服务】App Service 默认页面暴露Tomcat版本信息,存在安全风险
|
1月前
|
UED
|
15天前
|
Go 网络架构 开发者
Flutter &鸿蒙next中的路由使用详解【基础使用】
本文介绍了 Flutter 路由系统的使用方法,包括基本路由、命名路由、参数传递、返回参数和动态路由。通过 `Navigator` 类实现页面跳转,支持简单和复杂参数的传递,并可通过 `onGenerateRoute` 实现更灵活的动态路由管理。示例代码展示了如何在实际项目中应用这些技术,帮助开发者构建清晰、易于维护的导航结构。
62 1
|
1月前
|
Dart 开发者
flutter:页面整合 (十)
本文档介绍了如何在 Flutter 应用中使用底部导航栏(`BottomNavigationBar`)和侧边栏(`Drawer`),包括简单的使用方法、属性配置、与按钮结合使用、使用图片作为图标、以及如何实现顶部导航。示例代码展示了如何创建包含多个页面的导航栏,并通过 `TabController` 控制器实现页面切换。同时,文档还提供了如何自定义导航栏样式和添加浮动操作按钮(`FloatingActionButton`)的方法。最后,整合了底部导航栏、侧边栏和顶部导航栏的完整示例代码,帮助开发者快速构建具有导航功能的 Flutter 应用界面。
|
1月前
|
UED 开发者
flutter:获取对象&路由管理 (四)
本文介绍了Flutter中如何通过Context获取状态对象、使用GlobalKey获取状态对象、基本的路由管理、路由传值、命名路由、返回根路由以及点击图标跳转的方法。示例代码展示了如何在应用中实现这些功能,包括页面跳转、传递参数和返回上一页等操作。
|
1月前
|
前端开发 UED 开发者
uni-app:去除导航栏&跨域的问题&blobe查看图片&v-deep&页面操作 (五)
本文介绍了几个前端开发技巧:1) 如何通过设置 `navigationStyle` 为 `custom` 去除顶部导航;2) 解决跨域问题的方法,包括使用 `dotenv` 加载全局变量和配置 `devServer` 的代理;3) 使用 Blob 和 FileReader 查看图片;4) 利用 `v-deep` 深度作用选择器修改样式;5) 修改页面左上角返回按钮的行为。
|
3月前
|
应用服务中间件 Linux 网络安全
【Azure 应用服务】App Service for Linux 环境中为Tomcat页面修改默认的Azure 404页面
【Azure 应用服务】App Service for Linux 环境中为Tomcat页面修改默认的Azure 404页面
|
3月前
|
安全 JavaScript 应用服务中间件
【Azure Function App】如何修改Azure函数应用的默认页面呢?
【Azure Function App】如何修改Azure函数应用的默认页面呢?
|
3月前
|
JavaScript 前端开发
【Azure Developer】在App Service上放置一个JS页面并引用msal.min.js成功获取AAD用户名示例
【Azure Developer】在App Service上放置一个JS页面并引用msal.min.js成功获取AAD用户名示例