{"id":19273026,"url":"https://github.com/fluttercandies/ff_annotation_route","last_synced_at":"2025-04-06T15:11:54.269Z","repository":{"id":35070002,"uuid":"203153288","full_name":"fluttercandies/ff_annotation_route","owner":"fluttercandies","description":"Provide route generator to create route map quickly by annotations.","archived":false,"fork":false,"pushed_at":"2025-03-17T03:03:47.000Z","size":2885,"stargazers_count":123,"open_issues_count":0,"forks_count":24,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-30T14:22:52.039Z","etag":null,"topics":["annotation","flutter","rotue"],"latest_commit_sha":null,"homepage":null,"language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fluttercandies.png","metadata":{"files":{"readme":"README-ZH.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"custom":"http://zmtzawqlp.gitee.io/my_images/images/qrcode.png"}},"created_at":"2019-08-19T10:44:51.000Z","updated_at":"2025-03-17T09:50:11.000Z","dependencies_parsed_at":"2023-01-15T13:11:32.076Z","dependency_job_id":"47f84961-5209-435a-bf83-c4edb3a0e7c5","html_url":"https://github.com/fluttercandies/ff_annotation_route","commit_stats":{"total_commits":217,"total_committers":4,"mean_commits":54.25,"dds":0.4608294930875576,"last_synced_commit":"02e64d8d5a61260eedacafb41a351baf35cc796e"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Fff_annotation_route","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Fff_annotation_route/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Fff_annotation_route/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Fff_annotation_route/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fluttercandies","download_url":"https://codeload.github.com/fluttercandies/ff_annotation_route/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247500468,"owners_count":20948880,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["annotation","flutter","rotue"],"created_at":"2024-11-09T20:40:08.822Z","updated_at":"2025-04-06T15:11:54.238Z","avatar_url":"https://github.com/fluttercandies.png","language":"Dart","funding_links":["http://zmtzawqlp.gitee.io/my_images/images/qrcode.png"],"categories":[],"sub_categories":[],"readme":"# ff_annotation_route\n\n[![pub package](https://img.shields.io/pub/v/ff_annotation_route.svg)](https://pub.dartlang.org/packages/ff_annotation_route) [![GitHub stars](https://img.shields.io/github/stars/fluttercandies/ff_annotation_route)](https://github.com/fluttercandies/ff_annotation_route/stargazers) [![GitHub forks](https://img.shields.io/github/forks/fluttercandies/ff_annotation_route)](https://github.com/fluttercandies/ff_annotation_route/network) [![GitHub license](https://img.shields.io/github/license/fluttercandies/ff_annotation_route)](https://github.com/fluttercandies/ff_annotation_route/blob/master/LICENSE) [![GitHub issues](https://img.shields.io/github/issues/fluttercandies/ff_annotation_route)](https://github.com/fluttercandies/ff_annotation_route/issues) \u003ca target=\"_blank\" href=\"https://jq.qq.com/?_wv=1027\u0026k=5bcc0gy\"\u003e\u003cimg border=\"0\" src=\"https://pub.idqqimg.com/wpa/images/group.png\" alt=\"flutter-candies\" title=\"flutter-candies\"\u003e\u003c/a\u003e\n\nLanguages: [English](README.md) | 中文简体\n\n[掘金地址](https://juejin.im/post/5d5a7fe5f265da03b94ff42c)\n\n## 描述\n\n通过注解快速完成路由映射.\n\n- [ff\\_annotation\\_route](#ff_annotation_route)\n  - [描述](#描述)\n  - [使用](#使用)\n    - [增加引用](#增加引用)\n    - [添加注解](#添加注解)\n      - [空构造](#空构造)\n      - [带参数构造](#带参数构造)\n      - [FFRoute](#ffroute)\n    - [生成文件](#生成文件)\n      - [环境](#环境)\n      - [激活](#激活)\n      - [执行命令](#执行命令)\n      - [命令参数](#命令参数)\n    - [Navigator 1.0](#navigator-10)\n      - [Main.dart](#maindart)\n      - [Push](#push)\n        - [Push name](#push-name)\n        - [Push name with arguments](#push-name-with-arguments)\n    - [Navigator 2.0](#navigator-20)\n      - [Main.dart](#maindart-1)\n      - [FFRouteInformationParser](#ffrouteinformationparser)\n      - [FFRouterDelegate](#ffrouterdelegate)\n      - [Push](#push-1)\n        - [Push name](#push-name-1)\n        - [Push name with arguments](#push-name-with-arguments-1)\n    - [GetX](#getx)\n      - [How to use](#how-to-use)\n      - [设置 GetPageRoute 的参数](#设置-getpageroute-的参数)\n    - [Functional Widget](#functional-widget)\n      - [如何与 functional\\_widget 一起使用？](#如何与-functional_widget-一起使用)\n    - [Code Hints](#code-hints)\n  - [我可以不用,但你必须要有](#我可以不用但你必须要有)\n    - [Interceptor](#interceptor)\n      - [Route Interceptor](#route-interceptor)\n        - [实现 `RouteInterceptor`](#实现-routeinterceptor)\n        - [添加注解 `interceptors`](#添加注解-interceptors)\n        - [生成映射](#生成映射)\n        - [完成配置](#完成配置)\n      - [Global Interceptor](#global-interceptor)\n        - [实现 RouteInterceptor](#实现-routeinterceptor-1)\n        - [完成配置](#完成配置-1)\n      - [跳转](#跳转)\n    - [Lifecycle](#lifecycle)\n      - [RouteLifecycleState](#routelifecyclestate)\n      - [ExtendedRouteObserver](#extendedrouteobserver)\n    - [GlobalNavigator](#globalnavigator)\n  - [来杯可乐](#来杯可乐)\n\n## 使用\n\n### 增加引用\n\n添加引用到`dependencies`，及你需要注解的 project/packages 到`pubspec.yaml`中\n\n``` yaml\ndependencies:\n  # 如果是一个package，只用添加 ff_annotation_route_core\n  ff_annotation_route_core: any\n  # 如果是一个主项目，只需要添加 ff_annotation_route_library\n  ff_annotation_route_library: any\n``` \n\n执行 `flutter packages get` 下载\n\n### 添加注解\n\n#### 空构造\n\n```dart\nimport 'package:ff_annotation_route/ff_annotation_route.dart';\n\n@FFRoute(\n  name: \"fluttercandies://mainpage\",\n  routeName: \"MainPage\",\n)\nclass MainPage extends StatelessWidget\n{\n  // ...\n}\n\n```\n\n#### 带参数构造\n\n工具会自动处理带参数的构造，不需要做特殊处理。唯一需要注意的是，你需要使用 `argumentImports` 为class/enum的参数提供 import 地址。现在你可以使用 `@FFAutoImport()` 来替代.\n\n当然你现在可以选使用 `--no-fast-mode` 非快速模式进行解析，它会自动添加参数对应的引用。\n\n\n```dart\n@FFAutoImport('hide TestMode2')\nimport 'package:example1/src/model/test_model.dart';\n@FFAutoImport()\nimport 'package:example1/src/model/test_model1.dart' hide TestMode3;\nimport 'package:ff_annotation_route_library/ff_annotation_route_library.dart';\n\n@FFRoute(\n  name: 'flutterCandies://testPageE',\n  routeName: 'testPageE',\n  description: 'Show how to push new page with arguments(class)',\n  // 为了防止 @FFAutoImport() 不能完全表达的情况， 依然保留 argumentImports。\n  // argumentImports: \u003cString\u003e[\n  //   'import \\'package:example1/src/model/test_model.dart\\';',\n  //   'import \\'package:example1/src/model/test_model1.dart\\';',\n  // ],\n  exts: \u003cString, dynamic\u003e{\n    'group': 'Complex',\n    'order': 1,\n  },\n)\nclass TestPageE extends StatelessWidget {\n  const TestPageE({\n    this.testMode = const TestMode(\n      id: 2,\n      isTest: false,\n    ),\n    this.testMode1,\n  });\n  factory TestPageE.deafult() =\u003e TestPageE(\n        testMode: TestMode.deafult(),\n      );\n\n  factory TestPageE.required({@required TestMode testMode}) =\u003e TestPageE(\n        testMode: testMode,\n      );\n\n  final TestMode testMode;\n  final TestMode1 testMode1;\n}\n```\n\n#### FFRoute\n\n| Parameter       | Description                                                                                                                                                         | Default  |\n| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |\n| name            | 路由的名字 (e.g., \"/settings\")                                                                                                                                      | required |\n| showStatusBar   | 是否显示状态栏                                                                                                                                                      | true     |\n| routeName       | 用于埋点收集数据的页面名字                                                                                                                                          | ''       |\n| pageRouteType   | 路由的类型 (material, cupertino, transparent)                                                                                                                       | -        |\n| description     | 路由的描述                                                                                                                                                          | ''       |\n| exts            | 其他扩展参数.                                                                                                                                                       | -        |\n| argumentImports | 某些参数的导入.有一些参数是类或者枚举，需要指定它们的导入地址.现在你可以使用 @FFAutoImport()来替代                                                                  | -        |\n| codes           | 有些代码无法直接写在注释里面, 你可以使用该参数，生成路由的时候会生成对应代码. [see](https://github.com/fluttercandies/ff_annotation_route/tree/master/example_getx) | -        |\n### 生成文件\n\n#### 环境\n\n添加 dart 的 bin 的路径到你的系统 `$PATH`.\n\n`cache\\dart-sdk\\bin`\n\n[更多信息](https://dart.dev/tools/pub/cmd/pub-global)\n\n不清楚的可以看[掘金](https://juejin.im/post/5d4b8959e51d4561df780555)\n\n#### 激活\n\n`dart pub global activate ff_annotation_route`\n\n#### 执行命令\n\n到你的项目根目录下面执行.\n\n`ff_route \u003ccommand\u003e [arguments]`\n\n#### 命令参数\n\n可用的命令:\n\n``` markdown\n-h, --[no-]help                   帮助信息。\n\n-p, --path                        执行命令的目录，默认当前目录。\n\n-o, --output                      route 和 helper 文件的输出目录路径，路径相对于主项目的 lib 文件夹。\n\n-n, --name                        路由常量类的名称，默认为 `Routes`。\n\n-g, --git                         扫描 git 引用的 package，你需要指定 package 的名字，多个用 `,` 分开    \n    --exclude-packages            排除某些 packages 被扫描\n    --routes-file-output          routes 文件的输出目录路径，路径相对于主项目的lib文件夹\n    --const-ignore                使用正则表达式忽略一些const(不是全部const都希望生成)\n    --[no-]route-constants        是否在根项目中的 `xxx_route.dart` 生成全部路由的静态常量\n    --[no-]package                这个是否是一个 package\n    --[no-]super-arguments        是否生成路由参数帮助类\n\n-s, --[no-]save                   是否保存命令到本地。如果保存了，下一次就只需要执行 `ff_route` 就可以了。\n    --[no-]null-safety            是否支持空安全，默认 `true`\n    --[no-]fast-mode              快速模式: 只会对单独文件进行解析, 它更快.\n                                  非快速模式: 会对 packages 和 sdk 进行解析, 支持构造超级参数解析以及自动根据参数添加引用.\n                                  默认是快速模式    \n```\n\n### Navigator 1.0\n\n完整代码在 [example](https://github.com/fluttercandies/ff_annotation_route/tree/master/example) 中\n#### Main.dart\n\n```dart\nimport 'package:ff_annotation_route_library/ff_annotation_route_library.dart';\nimport 'package:flutter/material.dart';\nimport 'example_route.dart';\nimport 'example_routes.dart';\n\nvoid main() =\u003e runApp(MyApp());\n\nclass MyApp extends StatelessWidget {\n  // This widget is the root of your application.\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'ff_annotation_route demo',\n      debugShowCheckedModeBanner: false,\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      initialRoute: Routes.fluttercandiesMainpage,\n      onGenerateRoute: (RouteSettings settings) {\n        return onGenerateRoute(\n          settings: settings,\n          getRouteSettings: getRouteSettings,\n          routeSettingsWrapper: (FFRouteSettings ffRouteSettings) {\n            if (ffRouteSettings.name == Routes.fluttercandiesMainpage ||\n                ffRouteSettings.name ==\n                    Routes.fluttercandiesDemogrouppage.name) {\n              return ffRouteSettings;\n            }\n            return ffRouteSettings.copyWith(\n                widget: CommonWidget(\n              child: ffRouteSettings.widget,\n              title: ffRouteSettings.routeName,\n            ));\n          },\n        );\n      },\n    );\n  }\n}\n```\n#### Push\n\n##### Push name\n\n```dart\n  Navigator.pushNamed(context, Routes.fluttercandiesMainpage /* fluttercandies://mainpage */);\n```\n\n##### Push name with arguments\n\n* 参数必须是一个 `Map\u003cString, dynamic\u003e`\n\n```dart\n  Navigator.pushNamed(\n    context,\n    Routes.flutterCandiesTestPageE,\n    arguments: \u003cString, dynamic\u003e{\n      constructorName: 'required',\n      'testMode': const TestMode(\n        id: 100,\n        isTest: true,\n      ),\n    },\n  );\n```\n* 开启 --super-arguments\n\n```dart\n  Navigator.pushNamed(\n    context,\n    Routes.flutterCandiesTestPageE.name,\n    arguments: Routes.flutterCandiesTestPageE.requiredC(\n      testMode: const TestMode(\n        id: 100,\n        isTest: true,\n      ),\n    ),\n  );\n```\n\n### Navigator 2.0\n\n完整代码在 [example1](https://github.com/fluttercandies/ff_annotation_route/tree/master/example1) 中\n#### Main.dart\n\n```dart\nimport 'dart:convert';\nimport 'package:example1/src/model/test_model.dart';\nimport 'package:ff_annotation_route_library/ff_annotation_route_library.dart';\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter/material.dart';\nimport 'example1_route.dart';\nimport 'example1_routes.dart';\n\nvoid main() {\n  // 工具将处理简单的类型，但是没法处理全部的\n  // 比如在浏览器中输入以下地址\n  // http://localhost:64916/#flutterCandies://testPageF?list=[4,5,6]\u0026map={\"ddd\":123}\u0026testMode={\"id\":2,\"isTest\":true}\n  // queryParameters 将会根据你自身的情况转换成你对应的类型\n  FFConvert.convert = \u003cT\u003e(dynamic value) {\n    if (value == null) {\n      return null;\n    }\n    print(T);\n    final dynamic output = json.decode(value.toString());\n    if (\u003cint\u003e[] is T \u0026\u0026 output is List\u003cdynamic\u003e) {\n      return output.map\u003cint\u003e((dynamic e) =\u003e asT\u003cint\u003e(e)).toList() as T;\n    } else if (\u003cString, String\u003e{} is T \u0026\u0026 output is Map\u003cdynamic, dynamic\u003e) {\n      return output.map\u003cString, String\u003e((dynamic key, dynamic value) =\u003e\n          MapEntry\u003cString, String\u003e(key.toString(), value.toString())) as T;\n    } else if (const TestMode() is T \u0026\u0026 output is Map\u003cdynamic, dynamic\u003e) {\n      return TestMode.fromJson(output) as T;\n    }\n\n    return json.decode(value.toString()) as T;\n  };\n  runApp(MyApp());\n}\n\nclass MyApp extends StatelessWidget {\n  final FFRouteInformationParser _ffRouteInformationParser =\n      FFRouteInformationParser();\n\n  final FFRouterDelegate _ffRouterDelegate = FFRouterDelegate(\n    getRouteSettings: getRouteSettings,\n    pageWrapper: \u003cT\u003e(FFPage\u003cT\u003e ffPage) {\n      return ffPage.copyWith(\n        widget: ffPage.name == Routes.fluttercandiesMainpage ||\n                ffPage.name == Routes.fluttercandiesDemogrouppage.name\n            ? ffPage.widget\n            : CommonWidget(\n                child: ffPage.widget,\n                routeName: ffPage.routeName,\n              ),\n      );\n    },\n  );\n  // This widget is the root of your application.\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp.router(\n      title: 'ff_annotation_route demo',\n      debugShowCheckedModeBanner: false,\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      // 初始化第一个页面\n      routeInformationProvider: PlatformRouteInformationProvider(\n        initialRouteInformation: const RouteInformation(\n          location: Routes.fluttercandiesMainpage,\n        ),\n      ),\n      routeInformationParser: _ffRouteInformationParser,\n      routerDelegate: _ffRouterDelegate,\n    );\n  }\n}\n```\n\n#### FFRouteInformationParser\n\n用在 Web 平台，当你在浏览器上面输入的时候路由配置转换成为[RouteSettings]，或者当反馈给浏览器的时候将[RouteSettings]转换成路由配置\n\n举个例子:\n\n`xxx?a=1\u0026b=2` \u003c=\u003e `RouteSettings(name:'xxx',arguments:\u003cString, dynamic\u003e{'a':'1','b':'2'})`\n\n\n#### FFRouterDelegate\n\n用于创建和配置导航的委托，它提供 [Navigator] 中相似的方法.\n\n```dart\n  FFRouterDelegate.of(context).pushNamed\u003cvoid\u003e(\n    Routes.flutterCandiesTestPageF.name,\n    arguments: Routes.flutterCandiesTestPageF.d(\n      \u003cint\u003e[1, 2, 3],\n      map: \u003cString, String\u003e{'ddd': 'dddd'},\n      testMode: const TestMode(id: 1, isTest: true),\n    ),\n  );\n```\n\n你可以在 [test_page_c.dart](https://github.com/fluttercandies/ff_annotation_route/tree/master/example1/lib/src/pages/simple/test_page_c.dart) 页面里面找到更多的例子\n\n#### Push\n\n##### Push name\n\n```dart\n  FFRouterDelegate.of(context).pushNamed\u003cvoid\u003e(\n    Routes.flutterCandiesTestPageA,\n  );\n```\n\n##### Push name with arguments\n\n* 参数必须是一个 `Map\u003cString, dynamic\u003e`\n\n```dart\n  FFRouterDelegate.of(context).pushNamed\u003cvoid\u003e(\n    Routes.flutterCandiesTestPageF.name,\n    arguments: Routes.flutterCandiesTestPageF.d(\n      \u003cint\u003e[1, 2, 3],\n      map: \u003cString, String\u003e{'ddd': 'dddd'},\n      testMode: const TestMode(id: 1, isTest: true),\n    ),\n  );\n```\n* 开启 --super-arguments\n\n```dart\n  FFRouterDelegate.of(context).pushNamed\u003cvoid\u003e(\n    Routes.flutterCandiesTestPageF.name,\n    arguments: \u003cString, dynamic\u003e{\n        'list': \u003cint\u003e[1, 2, 3],\n        'map': \u003cString, String\u003e{'ddd': 'dddd'},\n        'testMode': const TestMode(id: 1, isTest: true),\n     }\n  )\n```\n\n### GetX\n\n#### How to use\n支持 Getx 的用法, 你只需要转换 `FFRouteSettings` 成为 `GetPageRoute`\n\n``` dart\nvoid main() =\u003e runApp(const MyApp());\n\nclass MyApp extends StatelessWidget {\n  const MyApp({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return GetMaterialApp(\n      title: 'ff_annotation_route demo',\n      debugShowCheckedModeBanner: false,\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      initialRoute: Routes.fluttercandiesMainpage.name,\n      onGenerateRoute: (RouteSettings settings) {\n        FFRouteSettings ffRouteSettings = getRouteSettings(\n          name: settings.name!,\n          arguments: settings.arguments as Map\u003cString, dynamic\u003e?,\n          notFoundPageBuilder: () =\u003e Scaffold(\n            appBar: AppBar(),\n            body: const Center(\n              child: Text('not find page'),\n            ),\n          ),\n        );\n        Bindings? binding;\n        if (ffRouteSettings.codes != null) {\n          binding = ffRouteSettings.codes!['binding'] as Bindings?;\n        }\n\n        Transition? transition;\n        bool opaque = true;\n        if (ffRouteSettings.pageRouteType != null) {\n          switch (ffRouteSettings.pageRouteType) {\n            case PageRouteType.cupertino:\n              transition = Transition.cupertino;\n              break;\n            case PageRouteType.material:\n              transition = Transition.downToUp;\n              break;\n            case PageRouteType.transparent:\n              opaque = false;\n              break;\n            default:\n          }\n        }\n\n        return GetPageRoute(\n          binding: binding,\n          opaque: opaque,\n          settings: ffRouteSettings,\n          transition: transition,\n          page: () =\u003e ffRouteSettings.builder(),\n        );\n      },\n    );\n  }\n}\n```\n\n#### 设置 GetPageRoute 的参数\n\n比如：\n'Bindings' 不是 const class, 所以它没法直接写在注解里面, 但是你可以这么做:\n\n1. 把它定义在 `codes` 里面\n2. 不要忘记添加对应的引用地址 `argumentImports`\n3. 最后在 `onGenerateRoute` 中获取到它\n\n``` dart\n@FFRoute(\n  name: \"/BindingsPage\",\n  routeName: 'BindingsPage',\n  description: 'how to use Bindings with Annotation.',\n  codes: \u003cString, String\u003e{\n    'binding': 'Bindings1()',\n  },\n  argumentImports: \u003cString\u003e[\n    'import \\'package:example_getx/src/bindings/bindings1.dart\\';'\n  ],\n)\n\n```\n\n``` dart\n      onGenerateRoute: (RouteSettings settings) {\n        FFRouteSettings ffRouteSettings = getRouteSettings(\n          name: settings.name!,\n          arguments: settings.arguments as Map\u003cString, dynamic\u003e?,\n          notFoundPageBuilder: () =\u003e Scaffold(\n            appBar: AppBar(),\n            body: const Center(\n              child: Text('not find page'),\n            ),\n          ),\n        );\n        Bindings? binding;\n        if (ffRouteSettings.codes != null) {\n          binding = ffRouteSettings.codes!['binding'] as Bindings?;\n        }\n\n        Transition? transition;\n        bool opaque = true;\n        if (ffRouteSettings.pageRouteType != null) {\n          switch (ffRouteSettings.pageRouteType) {\n            case PageRouteType.cupertino:\n              transition = Transition.cupertino;\n              break;\n            case PageRouteType.material:\n              transition = Transition.downToUp;\n              break;\n            case PageRouteType.transparent:\n              opaque = false;\n              break;\n            default:\n          }\n        }\n\n        return GetPageRoute(\n          binding: binding,\n          opaque: opaque,\n          settings: ffRouteSettings,\n          transition: transition,\n          page: () =\u003e ffRouteSettings.builder(),\n        );\n      },\n\n```\n\n\n### Functional Widget\n\n#### 如何与 [functional_widget](https://github.com/rrousselGit/functional_widget) 一起使用？\n\n```dart  \n@swidget\n@FFRoute(\n  name: 'flutterCandies://func1',\n  routeName: 'test-func-1',\n)\nWidget func1(\n  int a,\n  String? b, {\n  bool? c,\n  required double d,\n}) {\n  return Container();\n}\n```\n\n[示例代码](example/lib/src/pages/func/func.dart) 可以在这里找到.\n\n\n### Code Hints\n\n你能这样使用路由 'Routes.flutterCandiesTestPageE', 并且在编辑器中看到代码提示。\n包括页面描述，构造，参数类型，参数名字，参数是否必填。\n\n* 默认\n\n```dart\n  /// 'This is test page E.'\n  ///\n  /// [name] : 'flutterCandies://testPageE'\n  ///\n  /// [routeName] : 'testPageE'\n  ///\n  /// [description] : 'This is test page E.'\n  ///\n  /// [constructors] :\n  ///\n  /// TestPageE : [TestMode testMode, TestMode1 testMode1]\n  ///\n  /// TestPageE.deafult : []\n  ///\n  /// TestPageE.required : [TestMode(required) testMode]\n  ///\n  /// [exts] : {group: Complex, order: 1}\n  static const String flutterCandiesTestPageE = 'flutterCandies://testPageE';\n```\n\n* 开启 --super-arguments\n\n```dart\n  /// 'This is test page E.'\n  ///\n  /// [name] : 'flutterCandies://testPageE'\n  ///\n  /// [routeName] : 'testPageE'\n  ///\n  /// [description] : 'This is test page E.'\n  ///\n  /// [constructors] :\n  ///\n  /// TestPageE : [TestMode testMode, TestMode1 testMode1]\n  ///\n  /// TestPageE.test : []\n  ///\n  /// TestPageE.requiredC : [TestMode(required) testMode]\n  ///\n  /// [exts] : {group: Complex, order: 1}\n  static const _FlutterCandiesTestPageE flutterCandiesTestPageE =\n      _FlutterCandiesTestPageE();\n\n  class _FlutterCandiesTestPageE {\n    const _FlutterCandiesTestPageE();\n\n    String get name =\u003e 'flutterCandies://testPageE';\n\n    Map\u003cString, dynamic\u003e d(\n            {TestMode testMode = const TestMode(id: 2, isTest: false),\n            TestMode1 testMode1}) =\u003e\n        \u003cString, dynamic\u003e{\n          'testMode': testMode,\n          'testMode1': testMode1,\n        };\n\n    Map\u003cString, dynamic\u003e test() =\u003e const \u003cString, dynamic\u003e{\n          'constructorName': 'test',\n        };\n\n    Map\u003cString, dynamic\u003e requiredC({@required TestMode testMode}) =\u003e\n        \u003cString, dynamic\u003e{\n          'testMode': testMode,\n          'constructorName': 'requiredC',\n        };\n\n    @override\n    String toString() =\u003e name;\n  }\n\n```\n\n## 我可以不用,但你必须要有\n\n### Interceptor\n\n#### Route Interceptor\n\n\n##### 实现 `RouteInterceptor`\n针对某个页面进行跳转拦截，根据你的场景实现 `RouteInterceptor`。\n\n``` dart\nclass LoginInterceptor extends RouteInterceptor {\n  const LoginInterceptor();\n\n  @override\n  Future\u003cRouteInterceptResult\u003e intercept(\n    String routeName, {\n    Object? arguments,\n  }) async {\n    if (!User().hasLogin) {\n      return RouteInterceptResult.complete(\n        routeName: Routes.fluttercandiesLoginPage.name,\n      );\n    }\n\n    return RouteInterceptResult.next(\n      routeName: routeName,\n      arguments: arguments,\n    );\n  }\n}\n``` \n\n`RouteInterceptResult.complete` ，`RouteInterceptResult.next` 和 `RouteInterceptResult.abort` 对应的下面几种情况:  \n\n``` dart\n/// 表示路由拦截器在被调用后的可能动作\n/// 这些动作在路由拦截过程中执行。\nenum RouteInterceptAction {\n  /// 停止拦截链并取消任何后续操作。\n  /// 这表明当前拦截器已确定不应推送任何路由，\n  /// 导航过程将被中止。\n  abort,\n\n  /// 转到链中的下一个拦截器。\n  /// 这表明当前拦截器不想处理该路由，\n  /// 并将决策委托给后续的拦截器。\n  next,\n\n  /// 完成拦截过程并允许推送路由。\n  /// 这表明当前拦截器已处理该路由，\n  /// 导航应按预期继续进行。\n  complete,\n}\n``` \n\n\n##### 添加注解 `interceptors`\n\n为页面增加 `interceptors` 拦截器注解\n\n``` dart\n@FFRoute(\n  name: 'fluttercandies://PageA',\n  routeName: 'PageA',\n  description: 'PageA',\n  interceptors: \u003cRouteInterceptor\u003e[\n    LoginInterceptor(),\n  ],\n)\nclass PageA extends StatefulWidget {\n  const PageA({Key? key}) : super(key: key);\n\n  @override\n  State\u003cPageA\u003e createState() =\u003e _PageAState();\n}\n``` \n\n##### 生成映射\n\n执行 `ff_route`, 生成拦截器映射\n\n``` dart\n/// The routeInterceptors auto generated by https://github.com/fluttercandies/ff_annotation_route\nconst Map\u003cString, List\u003cRouteInterceptor\u003e\u003e routeInterceptors =\n    \u003cString, List\u003cRouteInterceptor\u003e\u003e{\n  'fluttercandies://PageA': \u003cRouteInterceptor\u003e[LoginInterceptor()],\n  'fluttercandies://PageB': \u003cRouteInterceptor\u003e[\n    LoginInterceptor(),\n    PermissionInterceptor()\n  ],\n};\n``` \n\n##### 完成配置\n\n``` dart\nvoid main() {\n  RouteInterceptorManager().addAllRouteInterceptors(routeInterceptors);\n  runApp(const MyApp());\n}\n``` \n\n#### Global Interceptor\n\n如果你不想在注解里面增加拦截器，你可以选择使用全局的拦截器。\n\n##### 实现 RouteInterceptor\n\n你可以在这里根据你的场景进行编写逻辑\n\n``` dart\nclass GlobalLoginInterceptor extends RouteInterceptor {\n  const GlobalLoginInterceptor();\n  @override\n  Future\u003cRouteInterceptResult\u003e intercept(String routeName,\n      {Object? arguments}) async {\n    if (routeName == Routes.fluttercandiesPageB.name ||\n        routeName == Routes.fluttercandiesPageA.name) {\n      if (!User().hasLogin) {\n        return RouteInterceptResult.complete(\n          routeName: Routes.fluttercandiesLoginPage.name,\n        );\n      }\n    }\n\n    return RouteInterceptResult.next(\n      routeName: routeName,\n      arguments: arguments,\n    );\n  }\n}\n``` \n\n##### 完成配置\n\n``` dart\nvoid main() {\n  RouteInterceptorManager().addGlobalInterceptors([\n    const GlobalLoginInterceptor(),\n    const GlobalPermissionInterceptor(),\n  ]);\n  runApp(const MyApp());\n}\n``` \n\n#### 跳转\n\n1. 你可以利用 `NavigatorWithInterceptorExtension` 扩展，调用带有 `WithInterceptor` 的方法\n\n``` dart\n    Navigator.of(context).pushNamedWithInterceptor(\n      Routes.fluttercandiesPageA.name,\n    );\n```\n\n2. 调用 `NavigatorWithInterceptor` 的静态方法\n   \n``` dart\n    NavigatorWithInterceptor.pushNamed(\n      context,\n      Routes.fluttercandiesPageB.name,\n    );\n```\n\n### Lifecycle\n\n#### RouteLifecycleState\n\n通过继承 `RouteLifecycleState`，你可以方便的感知页面的各种状态。\n\n只有当当前组件的承载是一个 `PageRoute`，才会触发 `onPageShow` 和 `onPageHide`。\n\n``` dart\nclass _PageBState extends RouteLifecycleState\u003cPageB\u003e {\n  @override\n  void onForeground() {\n    print('PageB onForeground');\n  }\n\n  @override\n  void onBackground() {\n    print('PageB onBackground');\n  }\n\n  @override\n  void onPageShow() {\n    print('PageB onPageShow');\n  }\n\n  @override\n  void onPageHide() {\n    print('PageB onPageHide');\n  }\n\n  @override\n  void onRouteShow() {\n    print('onRouteShow');\n  }\n\n  @override\n  void onRouteHide() {\n    print('onRouteHide');\n  }\n\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text('Page B'),\n      ),\n      body: GestureDetector(\n        onTap: () {},\n        child: const Center(\n          child: Text('This is Page B'),\n        ),\n      ),\n    );\n  }\n}\n``` \n\n#### ExtendedRouteObserver\n\n[ExtendedRouteObserver] 是一个扩展 Flutter 内置 RouteObserver 功能的工具类。\n它允许在导航栈中进行更高级的路由管理和跟踪。此类维护一个内部的活动路由列表，并提供\n若干用于路由检查和操作的实用方法。\n\n[ExtendedRouteObserver] 的主要特点：\n- 跟踪导航栈中的所有活动路由。\n- 通过 `topRoute` getter 提供对顶部路由的访问。\n- 通过 `containsRoute()` 方法检查特定路由是否存在于栈中。\n- 通过 `getRouteByName()` 方法根据名称检索路由。\n- 通过 `onRouteAdded` 和 `onRouteRemoved` 通知订阅者路由的添加或删除。\n- 通过 `onRouteAdd()` 和 `onRouteRemove()` 支持在路由添加或删除时执行自定义操作。\n\n当需要全球路由跟踪或高级导航行为时，此类非常有用，例如：\n- 监控当前活动的路由。\n- 基于当前路由栈处理自定义导航逻辑。\n- 实现导航历史记录功能或面包屑式导航。\n\n通过利用此类，开发者可以更好地了解和控制应用的导航状态。\n\n``` dart\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      navigatorObservers: \u003cNavigatorObserver\u003e[ExtendedRouteObserver()],\n    );\n  }\n``` \n\n### GlobalNavigator\n\nGlobalNavigator class is a utility class for managing global navigation actions.\nIt provides easy access to the Navigator and BuildContext from anywhere in the app.\n\n\n`context` 是 `Flutter` 中非常重要的一部分，涉及到很多关键的功能，比如主题、路由、依赖注入等。`Flutter` 的设计哲学是基于 `widget` 树的上下文传播，通过 `context` 来获取相关信息和功能，这样可以保持良好的组件分离和可维护性。\n\n通过全局 `navigatorKey` 来直接访问 `Navigator` 或 `context`，虽然在某些特定情况下是可以的，但不建议在常规情况下使用，特别是当 `Flutter` 的推荐模式（如通过 `context`）能很好地处理问题时。\n\n这种方式会带来一些潜在的问题：\n\n1. 违背 `Flutter` 的设计理念：`Flutter` 的设计初衷是基于 `BuildContext` 的局部导航和状态管理，通过全局方式绕过 `context`，可能会导致状态管理混乱，难以维护。\n\n2. 潜在的性能问题：全局访问 `context` 可能会绕过 `Flutter` 的优化机制，因为 `Flutter` 依赖于上下文树的结构来高效地更新 `UI`。\n\n3. 可维护性差：依赖全局导航会使代码变得难以理解和维护，特别是在应用规模变大时，可能很难追踪导航的流向和状态。\n\n``` dart\nimport 'package:flutter/material.dart';\n\nvoid main() {\n  runApp(MyApp());\n}\n\nclass MyApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      navigatorKey: GlobalNavigator.navigatorKey,  \n      home: HomeScreen(),\n    );\n  }\n}\n``` \n``` dart\n    GlobalNavigator.navigator?.push(\n      MaterialPageRoute(builder: (context) =\u003e SecondScreen()),\n    );\n``` \n\n``` dart\n    showDialog(\n      context: GlobalNavigator.context!,\n      builder: (b) {\n        return AlertDialog(\n          title: const Text('Permission Denied'),\n          content:\n              Text('You do not have permission to access this page.'),\n          actions: [\n            TextButton(\n              onPressed: () {\n                GlobalNavigator.navigator?.pop();\n              },\n              child: const Text('OK'),\n            ),\n          ],\n        );\n      },\n    );\n``` \n\n\n\n\n\n## 来杯可乐\n\n![img](http://zmtzawqlp.gitee.io/my_images/images/qrcode.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluttercandies%2Fff_annotation_route","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffluttercandies%2Fff_annotation_route","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluttercandies%2Fff_annotation_route/lists"}