- 作者:老汪软件技巧
- 发表时间:2024-09-30 00:02
- 浏览量:
一、需求来源
项目中需要判断路由堆栈是否包含哪个页面,如果包含就退回到此页面,如果没有就创建跳转。就是如此简单的需求困扰了半年多时间,今天看项目代码时偶然发现一种可能得实现方式,经过测试,完美解决此问题,可视为目前的最佳实践。
二、寻找解决之道
1、之前知道sdk中有 RouteAware 的堆栈数组,但是 _listeners 是私有属性,此路不通。
class RouteObserver extends Route> extends NavigatorObserver {
...
final Map<R, Set<RouteAware>> _listeners = <R, Set<RouteAware>>{};
...
}
2、stackflow 上没找到。
3、把 getx 的issues 都翻遍了也没有找到合适的解决办法。
三、解决之道
当偶然看到同事用监听器只获取当前路由时,突然发现这不正是我苦苦寻找良久的路由堆栈监听的切入口嘛。官方不暴露堆栈我自己实现一个不就完了。
class CustomRouteObserver extends RouteObserver<PageRoute<dynamic>> {
@override
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
super.didPush(route, previousRoute);
...
}
@override
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
super.didPop(route, previousRoute);
...
}
四、route_stack_manager 使用
navigatorObservers: [
RouteManagerObserver(),
],
in PageFive:
void onNext() {
DLog.d(RouteManager().toString());
}
打印:
[log] DLog 2024-09-28 10:46:16.173479 RouteManager: {
"isDebug": true,
"routes": [
"MaterialPageRoute(RouteSettings(" /", null), animation: AnimationController#38614(⏭ 1.000; paused; for MaterialPageRoute(/)))" ,
"MaterialPageRoute(RouteSettings(" /PageOne", null), animation: AnimationController#bd787(⏭ 1.000; paused; for MaterialPageRoute(/PageOne)))" ,
"MaterialPageRoute(RouteSettings(" /PageTwo", null), animation: AnimationController#e1844(⏭ 1.000; paused; for MaterialPageRoute(/PageTwo)))" ,
"MaterialPageRoute(RouteSettings(" /PageThree", null), animation: AnimationController#4492e(⏭ 1.000; paused; for MaterialPageRoute(/PageThree)))" ,
"MaterialPageRoute(RouteSettings(" /PageFour", null), animation: AnimationController#a9e6b(⏭ 1.000; paused; for MaterialPageRoute(/PageFour)))" ,
"MaterialPageRoute(RouteSettings(" /PageFive", null), animation: AnimationController#911b9(⏭ 1.000; paused; for MaterialPageRoute(/PageFive)))"
],
"routeNames": [
"/",
"/PageOne",
"/PageTwo",
"/PageThree",
"/PageFour",
"/PageFive"
],
"preRouteName": "/PageFour",
"current": "/PageFive"
}
五、源码1、定义堆栈管理监听数据类 RouteManager
//
// RouteManager.dart
// route_stack_manager
//
// Created by shang on 2024/9/28 09:51.
// Copyright © 2024/9/28 shang. All rights reserved.
//
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'dart:developer' as developer;
/// 路由堆栈管理器
class RouteManager {
static final RouteManager _instance = RouteManager._();
RouteManager._();
factory RouteManager() => _instance;
static RouteManager get instance => _instance;
/// 是都打印日志
bool isDebug = false;
/// 路由堆栈
final Listdynamic>> _routes = [];
/// 当前路由堆栈
Listdynamic>> get routes => _routes;
/// 当前路由名堆栈
List<String?> get routeNames => routes.map((e) => e.settings.name).toList();
/// 之前路由
Route<dynamic>? preRoute;
/// 当前路由
String? get preRouteName => preRoute?.settings.name;
/// 当前路由
Route<dynamic>? get lastRoute => routes.isEmpty ? null : routes.last;
/// 当前路由
String? get current => lastRoute?.settings.name;
/// 进出堆栈过滤条件(默认仅支持PageRoute, 过滤弹窗)
bool Function(Route<dynamic> route) filterRoute =
(route) => route is PageRoute && route.settings.name != null;
/// 更新回调
ValueChanged? onChanged;
/// 是否存在路由堆栈中
bool contain(String routeName) {
return routeNames.contains(routeName);
}
/// 路由对应的参数
Object? getArguments(String routeName) {
final route = routes.firstWhere((e) => e.settings.name == routeName);
return route.settings.arguments;
}
/// 入栈
void push(Route<dynamic> route) {
if (!filterRoute(route)) {
debugPrint("❌push ${[route.runtimeType, route.settings.name]}");
return;
}
if (_routes.isNotEmpty &&
_routes.last.settings.name == route.settings.name) {
return;
}
_routes.add(route);
}
/// 出栈
void pop(Route<dynamic> route) {
if (!filterRoute(route)) {
return;
}
_routes.removeWhere((e) => e.settings.name == route.settings.name);
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['isDebug'] = isDebug;
data['routes'] = routes.map((e) => e.toString()).toList();
data['routeNames'] = routeNames;
data['preRouteName'] = preRouteName;
data['current'] = current;
return data;
}
@override
String toString() {
const encoder = JsonEncoder.withIndent(' ');
final descption = encoder.convert(toJson());
return "$runtimeType: $descption";
}
void logRoutes() {
onChanged?.call(this);
if (!isDebug) {
return;
}
developer.log(toString());
}
}
2、定义堆栈管理监听器类 RouteManagerObserver
//
// RouteManagerObserver.dart
// route_stack_manager
//
// Created by shang on 2024/9/28 09:51.
// Copyright © 2024/9/28 shang. All rights reserved.
//
import 'package:flutter/cupertino.dart';
import 'route_manager.dart';
/// 堆栈管理器路由监听器
class RouteManagerObserver extends RouteObserver<PageRoute> {
PageRoute? currentRoute;
@override
void didPush(Route route, Route? previousRoute ) {
super.didPush(route, previousRoute);
RouteManager().push(route);
RouteManager().preRoute = previousRoute;
RouteManager().logRoutes();
}
@override
void didPop(Route route, Route? previousRoute ) {
super.didPop(route, previousRoute);
RouteManager().pop(route);
RouteManager().preRoute = route;
RouteManager().logRoutes();
}
@override
void didReplace({Route? newRoute, Route? oldRoute} ) {
super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
if (oldRoute != null && newRoute != null) {
RouteManager().pop(oldRoute);
RouteManager().push(newRoute);
RouteManager().preRoute = oldRoute;
RouteManager().logRoutes();
}
}
@override
void didRemove(Route route, Route? previousRoute ) {
super.didRemove(route, previousRoute);
RouteManager().pop(route);
RouteManager().logRoutes();
}
}
总结1、核心思路是通过 RouteObserver 为切入点,自己定义路由管理堆栈。2、Route route 有可能是 bottomSheet 等其他类型;默认只保留 PageRoute,可通过 filterRoute 方法自定义过滤条件;3、已封装为 package 库 route_stack_manager
github