likes
comments
collection
share

Flutter 我可以不用,但你必须要有!我可以不用,但你必须要有!开发者就是上帝,一直是我们的宗旨。对于合理的要求,我

作者站长头像
站长
· 阅读数 23

勿忘国耻,吾辈自强

手上没有剑和有剑不用不是一回事,铭记历史,勿忘国耻!

相关阅读

Flutter 我可以不用,但你必须要有!我可以不用,但你必须要有!开发者就是上帝,一直是我们的宗旨。对于合理的要求,我

前言

经常在群里听到大家吐槽 Flutter 的路由不好用.

我: ??? 没人用法法路由?

上帝: 法法路由不支持路由拦截(Route Guard),路由生命周期监听,巴拉巴拉......

我: 这些功能不是很简单就实现了吗? 封装一下?这些功能也不是都需要用到吧?

上帝: 我可以不用,但你必须要有!

我: 好好好,这样搞?

我可以不用,但你必须要有

拦截器

路由拦截器,主要用权限验证数据预加载路径重定向 等场景。

单页面拦截器
实现 RouteInterceptor

针对某个页面进行跳转拦截,根据你的场景实现 RouteInterceptor

class LoginInterceptor extends RouteInterceptor {
  const LoginInterceptor();

  @override
  Future<RouteInterceptResult> intercept(
    String routeName, {
    Object? arguments,
  }) async {
    if (!User().hasLogin) {
      return RouteInterceptResult.complete(
        routeName: Routes.fluttercandiesLoginPage.name,
      );
    }

    return RouteInterceptResult.next(
      routeName: routeName,
      arguments: arguments,
    );
  }
}

RouteInterceptResult.completeRouteInterceptResult.nextRouteInterceptResult.abort 对应的是下面几种情况:

/// 表示路由拦截器在被调用后的可能动作
/// 这些动作在路由拦截过程中执行。
enum RouteInterceptAction {
  /// 停止拦截链并取消任何后续操作。
  /// 这表明当前拦截器已确定不应推送任何路由,
  /// 导航过程将被中止。
  abort,

  /// 转到链中的下一个拦截器。
  /// 这表明当前拦截器不想处理该路由,
  /// 并将决策委托给后续的拦截器。
  next,

  /// 完成拦截过程并允许推送路由。
  /// 这表明当前拦截器已处理该路由,
  /// 导航应按预期继续进行。
  complete,
}
添加注解 interceptors

为页面增加 interceptors 拦截器注解

@FFRoute(
  name: 'fluttercandies://PageA',
  routeName: 'PageA',
  description: 'PageA',
  interceptors: <RouteInterceptor>[
    LoginInterceptor(),
  ],
)
class PageA extends StatefulWidget {
  const PageA({Key? key}) : super(key: key);

  @override
  State<PageA> createState() => _PageAState();
}
生成映射

执行 ff_route, 生成拦截器映射

/// The routeInterceptors auto generated by https://github.com/fluttercandies/ff_annotation_route
const Map<String, List<RouteInterceptor>> routeInterceptors =
    <String, List<RouteInterceptor>>{
  'fluttercandies://PageA': <RouteInterceptor>[LoginInterceptor()],
  'fluttercandies://PageB': <RouteInterceptor>[
    LoginInterceptor(),
    PermissionInterceptor()
  ],
};
完成配置
void main() {
  RouteInterceptorManager().addAllRouteInterceptors(routeInterceptors);
  runApp(const MyApp());
}
全局拦截器

如果你不想在注解里面增加拦截器,你可以选择使用全局的拦截器。

实现 RouteInterceptor

你可以在这里根据你的场景进行编写逻辑

class GlobalLoginInterceptor extends RouteInterceptor {
  const GlobalLoginInterceptor();
  @override
  Future<RouteInterceptResult> intercept(String routeName,
      {Object? arguments}) async {
    if (routeName == Routes.fluttercandiesPageB.name ||
        routeName == Routes.fluttercandiesPageA.name) {
      if (!User().hasLogin) {
        return RouteInterceptResult.complete(
          routeName: Routes.fluttercandiesLoginPage.name,
        );
      }
    }

    return RouteInterceptResult.next(
      routeName: routeName,
      arguments: arguments,
    );
  }
}
完成配置
void main() {
  RouteInterceptorManager().addGlobalInterceptors([
    const GlobalLoginInterceptor(),
    const GlobalPermissionInterceptor(),
  ]);
  runApp(const MyApp());
}
跳转
  1. 你可以利用 NavigatorWithInterceptorExtension 扩展,调用带有 WithInterceptor 的方法
    Navigator.of(context).pushNamedWithInterceptor(
      Routes.fluttercandiesPageA.name,
    );
  1. 调用 NavigatorWithInterceptor 的静态方法
    NavigatorWithInterceptor.pushNamed(
      context,
      Routes.fluttercandiesPageB.name,
    );

Lifecycle

RouteLifecycleState

通过继承 RouteLifecycleState,你可以方便的感知页面的各种状态。

只有当当前组件的承载是一个 PageRoute,才会触发 onPageShowonPageHide。 弹框会触发onRouteShowonRouteHide,不会触发 onPageShowonPageHide

class _PageBState extends RouteLifecycleState<PageB> {
  @override
  void onForeground() {
    print('PageB onForeground');
  }

  @override
  void onBackground() {
    print('PageB onBackground');
  }

  @override
  void onPageShow() {
    print('PageB onPageShow');
  }

  @override
  void onPageHide() {
    print('PageB onPageHide');
  }

  @override
  void onRouteShow() {
    print('onRouteShow');
  }

  @override
  void onRouteHide() {
    print('onRouteHide');
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Page B'),
      ),
      body: GestureDetector(
        onTap: () {},
        child: const Center(
          child: Text('This is Page B'),
        ),
      ),
    );
  }
}
ExtendedRouteObserver

ExtendedRouteObserver 是一个扩展 Flutter 内置 RouteObserver 功能的工具类。 它允许在导航栈中进行更高级的路由管理和跟踪。此类维护一个内部的活动路由列表,并提供 若干用于路由检查和操作的实用方法。

ExtendedRouteObserver 的主要特点:

  • 跟踪导航栈中的所有活动路由。
  • 通过 topRoute getter 提供对顶部路由的访问。
  • 通过 containsRoute() 方法检查特定路由是否存在于栈中。
  • 通过 getRouteByName() 方法根据名称检索路由。
  • 通过 onRouteAddedonRouteRemoved 通知订阅者路由的添加或删除。
  • 通过 onRouteAdd()onRouteRemove() 支持在路由添加或删除时执行自定义操作。

当需要全球路由跟踪或高级导航行为时,此类非常有用,例如:

  • 监控当前活动的路由。
  • 基于当前路由栈处理自定义导航逻辑。
  • 实现导航历史记录功能或面包屑式导航。

通过利用此类,开发者可以更好地了解和控制应用的导航状态。

  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorObservers: <NavigatorObserver>[ExtendedRouteObserver()],
    );
  }

GlobalNavigator

GlobalNavigator 类是一个用于管理全局导航操作的工具类。它提供了从应用程序的任何地方轻松访问 NavigatorBuildContext 的功能。

contextFlutter 中非常重要的一部分,涉及到很多关键的功能,比如主题、路由、依赖注入等。Flutter 的设计哲学是基于 widget 树的上下文传播,通过 context 来获取相关信息和功能,这样可以保持良好的组件分离和可维护性。

通过全局 navigatorKey 来直接访问 Navigatorcontext,虽然在某些特定情况下是可以的,但不建议在常规情况下使用,特别是当 Flutter 的推荐模式(如通过 context)能很好地处理问题时。

这种方式会带来一些潜在的问题:

  1. 违背 Flutter 的设计理念:Flutter 的设计初衷是基于 BuildContext 的局部导航和状态管理,通过全局方式绕过 context,可能会导致状态管理混乱,难以维护。

  2. 潜在的性能问题:全局访问 context 可能会绕过 Flutter 的优化机制,因为 Flutter 依赖于上下文树的结构来高效地更新 UI

  3. 可维护性差:依赖全局导航会使代码变得难以理解和维护,特别是在应用规模变大时,可能很难追踪导航的流向和状态。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: GlobalNavigator.navigatorKey,  
      home: HomeScreen(),
    );
  }
}
    GlobalNavigator.navigator?.push(
      MaterialPageRoute(builder: (context) => SecondScreen()),
    );
    showDialog(
      context: GlobalNavigator.context!,
      builder: (b) {
        return AlertDialog(
          title: const Text('Permission Denied'),
          content:
              Text('You do not have permission to access this page.'),
          actions: [
            TextButton(
              onPressed: () {
                GlobalNavigator.navigator?.pop();
              },
              child: const Text('OK'),
            ),
          ],
        );
      },
    );

总结就是,提供了,但是不建议使用。

结语

开发者就是上帝,一直是我们的宗旨。对于合理的要求,我们总是快速响应,有求必应。

Flutter 我可以不用,但你必须要有!我可以不用,但你必须要有!开发者就是上帝,一直是我们的宗旨。对于合理的要求,我

Flutter,爱糖果,欢迎加入Flutter Candies,一起生产可爱的Flutter小糖果Flutter 我可以不用,但你必须要有!我可以不用,但你必须要有!开发者就是上帝,一直是我们的宗旨。对于合理的要求,我QQ群:181398081

最最后放上 Flutter Candies 全家桶,真香。

Flutter 我可以不用,但你必须要有!我可以不用,但你必须要有!开发者就是上帝,一直是我们的宗旨。对于合理的要求,我

转载自:https://juejin.cn/post/7415659129039880192
评论
请登录