Flutter 我可以不用,但你必须要有!
点击关注公众号,“技术干货”及时达!前言经常在群里听到大家吐槽 Flutter 的路由不好用.
?我: ???没人用法法路由?
??上帝: 法法路由不支持路由拦截(Route Guard),路由生命周期监听,巴拉巴拉......
??我: 这些功能不是很简单就实现了吗?封装一下?这些功能也不是都需要用到吧?
??上帝: 我可以不用,但你必须要有!
??我: 好好好,这样搞?
?我可以不用,但你必须要有拦截器路由拦截器,主要用「权限验证」,「数据预加载」,「路径重定向」 等场景。
单页面拦截器实现 RouteInterceptor针对某个页面进行跳转拦截,根据你的场景实现 RouteInterceptor。
classLoginInterceptorextendsRouteInterceptor{
constLoginInterceptor();
@override
FutureRouteInterceptResultintercept(
StringrouteName,{
Object?arguments,
})async{
if(!User().hasLogin){
returnRouteInterceptResult.complete(
routeName:Routes.fluttercandiesLoginPage.name,
}
returnRouteInterceptResult.next(
routeName:routeName,
arguments:arguments,
}
}
RouteInterceptResult.complete ,RouteInterceptResult.next 和 RouteInterceptResult.abort 对应的是下面几种情况:
///表示路由拦截器在被调用后的可能动作
///这些动作在路由拦截过程中执行。
enumRouteInterceptAction{
///停止拦截链并取消任何后续操作。
///这表明当前拦截器已确定不应推送任何路由,
///导航过程将被中止。
abort,
///转到链中的下一个拦截器。
///这表明当前拦截器不想处理该路由,
///并将决策委托给后续的拦截器。
next,
///完成拦截过程并允许推送路由。
///这表明当前拦截器已处理该路由,
///导航应按预期继续进行。
complete,
}
添加注解 interceptors为页面增加 interceptors 拦截器注解
@FFRoute(
name:'fluttercandies://PageA',
routeName:'PageA',
description:'PageA',
interceptors:RouteInterceptor[
LoginInterceptor(),
],
)
classPageAextendsStatefulWidget{
constPageA({Key?key}):super(key:key);
@override
StatePageAcreateState()=_PageAState();
}
生成映射执行 ff_route, 生成拦截器映射
///TherouteInterceptorsautogeneratedbyhttps://github.com/fluttercandies/ff_annotation_route
constMapString,ListRouteInterceptorrouteInterceptors=
String,ListRouteInterceptor{
'fluttercandies://PageA':RouteInterceptor[LoginInterceptor()],
'fluttercandies://PageB':RouteInterceptor[
LoginInterceptor(),
PermissionInterceptor()
],
};
完成配置voidmain(){
RouteInterceptorManager().addAllRouteInterceptors(routeInterceptors);
runApp(constMyApp());
}
全局拦截器如果你不想在注解里面增加拦截器,你可以选择使用全局的拦截器。
实现 RouteInterceptor你可以在这里根据你的场景进行编写逻辑
classGlobalLoginInterceptorextendsRouteInterceptor{
constGlobalLoginInterceptor();
@override
FutureRouteInterceptResultintercept(StringrouteName,
{Object?arguments})async{
if(routeName==Routes.fluttercandiesPageB.name||
routeName==Routes.fluttercandiesPageA.name){
if(!User().hasLogin){
returnRouteInterceptResult.complete(
routeName:Routes.fluttercandiesLoginPage.name,
}
}
returnRouteInterceptResult.next(
routeName:routeName,
arguments:arguments,
}
}
完成配置voidmain(){
RouteInterceptorManager().addGlobalInterceptors([
constGlobalLoginInterceptor(),
constGlobalPermissionInterceptor(),
runApp(constMyApp());
}
跳转你可以利用 NavigatorWithInterceptorExtension 扩展,调用带有 WithInterceptor 的方法Navigator.of(context).pushNamedWithInterceptor(
Routes.fluttercandiesPageA.name,
调用 NavigatorWithInterceptor 的静态方法NavigatorWithInterceptor.pushNamed(
context,
Routes.fluttercandiesPageB.name,
LifecycleRouteLifecycleState通过继承 RouteLifecycleState,你可以方便的感知页面的各种状态。
只有当当前组件的承载是一个 PageRoute,才会触发 onPageShow 和 onPageHide。弹框会触发onRouteShow 和 onRouteHide,不会触发 onPageShow 和 onPageHide。
class_PageBStateextendsRouteLifecycleStatePageB{
@override
voidonForeground(){
print('PageBonForeground');
}
@override
voidonBackground(){
print('PageBonBackground');
}
@override
voidonPageShow(){
print('PageBonPageShow');
}
@override
voidonPageHide(){
print('PageBonPageHide');
}
@override
voidonRouteShow(){
print('onRouteShow');
}
@override
voidonRouteHide(){
print('onRouteHide');
}
@override
Widgetbuild(BuildContextcontext){
returnScaffold(
appBar:AppBar(
title:constText('PageB'),
),
body:GestureDetector(
onTap:(){},
child:constCenter(
child:Text('ThisisPageB'),
),
),
}
}
ExtendedRouteObserverExtendedRouteObserver 是一个扩展 Flutter 内置 RouteObserver 功能的工具类。它允许在导航栈中进行更高级的路由管理和跟踪。此类维护一个内部的活动路由列表,并提供
若干用于路由检查和操作的实用方法。
ExtendedRouteObserver 的主要特点:
跟踪导航栈中的所有活动路由。通过 topRoute getter 提供对顶部路由的访问。通过 containsRoute() 方法检查特定路由是否存在于栈中。通过 getRouteByName() 方法根据名称检索路由。通过 onRouteAdded 和 onRouteRemoved 通知订阅者路由的添加或删除。通过 onRouteAdd() 和 onRouteRemove() 支持在路由添加或删除时执行自定义操作。当需要全球路由跟踪或高级导航行为时,此类非常有用,例如:
监控当前活动的路由。基于当前路由栈处理自定义导航逻辑。实现导航历史记录功能或面包屑式导航。通过利用此类,开发者可以更好地了解和控制应用的导航状态。
Widgetbuild(BuildContextcontext){
returnMaterialApp(
navigatorObservers:NavigatorObserver[ExtendedRouteObserver()],
}
GlobalNavigatorGlobalNavigator 类是一个用于管理全局导航操作的工具类。它提供了从应用程序的任何地方轻松访问 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';
voidmain(){
runApp(MyApp());
}
classMyAppextendsStatelessWidget{
@override
Widgetbuild(BuildContextcontext){
returnMaterialApp(
navigatorKey:GlobalNavigator.navigatorKey,
home:HomeScreen(),
}
}
GlobalNavigator.navigator?.push(
MaterialPageRoute(builder:(context)=SecondScreen()),
showDialog(
context:GlobalNavigator.context!,
builder:(b){
returnAlertDialog(
title:constText('PermissionDenied'),
content:
Text('Youdonothavepermissiontoaccessthispage.'),
actions:[
TextButton(
onPressed:(){
GlobalNavigator.navigator?.pop();
},
child:constText('OK'),
),
],
},
?总结就是,提供了,但是不建议使用。
?结语开发者就是上帝,一直是我们的宗旨。对于合理的要求,我们总是快速响应,有求必应。
点击关注公众号,“技术干货”及时达!
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线