Files
record-tool/lib/app/router/app_navigator.dart
林锋 02c1c87b46 1. 升级依赖版本
2. 解决运行项目警告日志问题
3. 优化代码
2026-06-04 13:55:33 +08:00

190 lines
4.8 KiB
Dart

import 'dart:io';
import 'package:flutter/material.dart';
class AppNavigator {
AppNavigator._();
static final navigatorKey = GlobalKey<NavigatorState>();
static final Set<String> _pushingRoutes = <String>{};
static BuildContext? get context => navigatorKey.currentContext;
static Future<T?> push<T>(
Widget page, {
BuildContext? context,
Object? arguments,
String? name,
bool preventDuplicate = true,
}) async {
final routeName = name ?? page.runtimeType.toString();
if (preventDuplicate && RouteTracker.contains(routeName)) {
return null;
}
if (_pushingRoutes.contains(routeName)) {
return null;
}
_pushingRoutes.add(routeName);
final nav = Navigator.of(
context ?? AppNavigator.context!,
rootNavigator: true,
);
try {
return await nav.push<T>(
SlidePageRoute(
builder: (_) => page,
settings: RouteSettings(name: routeName, arguments: arguments),
),
);
} finally {
WidgetsBinding.instance.addPostFrameCallback((_) {
_pushingRoutes.remove(routeName);
});
}
}
static Future<T?> pushReplacement<T, TO>(
Widget page, {
BuildContext? context,
Object? arguments,
String? name,
}) {
return Navigator.of(
context ?? AppNavigator.context!,
rootNavigator: true,
).pushReplacement<T, TO>(
SlidePageRoute(
builder: (_) => page,
settings: RouteSettings(name: name, arguments: arguments),
),
);
}
static Future<T?> pushAndRemoveUntil<T>(
Widget page, {
BuildContext? context,
RoutePredicate? predicate,
Object? arguments,
String? name,
}) {
return Navigator.of(
context ?? AppNavigator.context!,
rootNavigator: true,
).pushAndRemoveUntil<T>(
SlidePageRoute(
builder: (_) => page,
settings: RouteSettings(name: name, arguments: arguments),
),
predicate ?? (_) => false,
);
}
static Future<T?> pushTransparent<T>(
Widget page, {
BuildContext? context,
Color barrierColor = Colors.black54,
Duration duration = const Duration(milliseconds: 200),
bool dismissible = true,
}) {
return Navigator.of(context ?? AppNavigator.context!).push<T>(
PageRouteBuilder<T>(
opaque: false,
barrierColor: barrierColor,
barrierDismissible: dismissible,
transitionDuration: duration,
reverseTransitionDuration: duration,
pageBuilder: (_, _, _) => page,
transitionsBuilder: (_, animation, _, child) {
return FadeTransition(opacity: animation, child: child);
},
),
);
}
static void pop<T extends Object?>({BuildContext? context, T? result}) {
Navigator.of(
context ?? AppNavigator.context!,
rootNavigator: true,
).pop<T>(result);
}
static void popTimes({BuildContext? context, int count = 1}) {
var popped = 0;
Navigator.of(context ?? AppNavigator.context!).popUntil((route) {
if (popped < count) {
popped++;
return false;
}
return true;
});
}
}
class SlidePageRoute<T> extends MaterialPageRoute<T> {
SlidePageRoute({required super.builder, super.settings});
@override
Widget buildTransitions(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
if (Platform.isAndroid) {
final tween = Tween(
begin: const Offset(1, 0),
end: Offset.zero,
).chain(CurveTween(curve: Curves.easeOutCubic));
return SlideTransition(position: animation.drive(tween), child: child);
}
return Theme.of(context).pageTransitionsTheme.buildTransitions<T>(
this,
context,
animation,
secondaryAnimation,
child,
);
}
}
class RouteTracker extends NavigatorObserver {
static final List<String?> pageStack = [];
bool _isPage(Route<dynamic> route) => route is PageRoute;
@override
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
if (_isPage(route)) {
pageStack.add(route.settings.name);
}
}
@override
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
if (_isPage(route) && pageStack.isNotEmpty) {
pageStack.removeLast();
}
}
@override
void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) {
if (_isPage(route)) {
pageStack.remove(route.settings.name);
}
}
@override
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
if (oldRoute != null && _isPage(oldRoute) && pageStack.isNotEmpty) {
pageStack.removeLast();
}
if (newRoute != null && _isPage(newRoute)) {
pageStack.add(newRoute.settings.name);
}
}
static bool contains(String name) => pageStack.contains(name);
}