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.complete
,RouteInterceptResult.next
和 RouteInterceptResult.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());
}
跳转
- 你可以利用
NavigatorWithInterceptorExtension
扩展,调用带有WithInterceptor
的方法
Navigator.of(context).pushNamedWithInterceptor(
Routes.fluttercandiesPageA.name,
);
- 调用
NavigatorWithInterceptor
的静态方法
NavigatorWithInterceptor.pushNamed(
context,
Routes.fluttercandiesPageB.name,
);
Lifecycle
RouteLifecycleState
通过继承 RouteLifecycleState
,你可以方便的感知页面的各种状态。
只有当当前组件的承载是一个 PageRoute
,才会触发 onPageShow
和 onPageHide
。
弹框会触发onRouteShow
和 onRouteHide
,不会触发 onPageShow
和 onPageHide
。
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()
方法根据名称检索路由。 - 通过
onRouteAdded
和onRouteRemoved
通知订阅者路由的添加或删除。 - 通过
onRouteAdd()
和onRouteRemove()
支持在路由添加或删除时执行自定义操作。
当需要全球路由跟踪或高级导航行为时,此类非常有用,例如:
- 监控当前活动的路由。
- 基于当前路由栈处理自定义导航逻辑。
- 实现导航历史记录功能或面包屑式导航。
通过利用此类,开发者可以更好地了解和控制应用的导航状态。
Widget build(BuildContext context) {
return MaterialApp(
navigatorObservers: <NavigatorObserver>[ExtendedRouteObserver()],
);
}
GlobalNavigator
GlobalNavigator
类是一个用于管理全局导航操作的工具类。它提供了从应用程序的任何地方轻松访问 Navigator
和 BuildContext
的功能。
context
是 Flutter
中非常重要的一部分,涉及到很多关键的功能,比如主题、路由、依赖注入等。Flutter
的设计哲学是基于 widget
树的上下文传播,通过 context
来获取相关信息和功能,这样可以保持良好的组件分离和可维护性。
通过全局 navigatorKey
来直接访问 Navigator
或 context
,虽然在某些特定情况下是可以的,但不建议在常规情况下使用,特别是当 Flutter
的推荐模式(如通过 context
)能很好地处理问题时。
这种方式会带来一些潜在的问题:
-
违背
Flutter
的设计理念:Flutter
的设计初衷是基于BuildContext
的局部导航和状态管理,通过全局方式绕过context
,可能会导致状态管理混乱,难以维护。 -
潜在的性能问题:全局访问
context
可能会绕过Flutter
的优化机制,因为Flutter
依赖于上下文树的结构来高效地更新UI
。 -
可维护性差:依赖全局导航会使代码变得难以理解和维护,特别是在应用规模变大时,可能很难追踪导航的流向和状态。
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 Candies,一起生产可爱的Flutter小糖果QQ群:181398081
最最后放上 Flutter Candies 全家桶,真香。
转载自:https://juejin.cn/post/7415659129039880192