假设您有一个带有4个图标的BottomNavigationBar
,它将导航到4个屏幕。当我这样做时:
A>B>D>B
我预计正常行为将弹出,直到第一个B,这使我的堆栈只剩下A>B.有了popUntil()
,我就能做到。但是,当使用popUntil()
并且堆栈中不存在B时,它会弹出整个堆栈。相反,如果B不存在,我希望pushNamed()
。既然我没有访问堆栈历史记录的权限,我该怎么做?
@GrahamD你是对的,我编辑过。
根据@GrahamD的建议,这是我目前的导航配置,对我来说有点粗糙,但有效:
main.dart
...
return MaterialApp(
navigatorObservers: [NavObserver()],
navigatorKey: serviceLocator<NavigationService>().navigatorKey,
onGenerateRoute: Router().generateRoute,
...
navigation_service.dart
class NavigationService {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
List<AppRoute> routeStack = [];
///navigate to destination and add destination to stack
void navigateTo(AppRoute destination, {Object arguments}) {
if (routeStack.isEmpty || routeStack.last != destination) {
navigatorKey.currentState
.pushNamed(destination.index.toString(), arguments: arguments);
}
}
///pushNamedAndRemoveUntil and add destination to stack after clearing it
void pushNamedAndRemoveUntil(AppRoute route, {Object arguments}) {
navigatorKey.currentState.pushNamedAndRemoveUntil(
route.index.toString(), (route) => false,
arguments: arguments);
}
///pop
void pop({Object arguments}) {
return navigatorKey.currentState.pop(arguments);
}
///if the route exists in the stack, popUntil, otherwise pushNamed
void popUntilOrPush(AppRoute route) {
if (routeStack.contains(route)) {
return navigatorKey.currentState
.popUntil(ModalRoute.withName(route.index.toString()));
} else {
navigateTo(route);
}
}
}
class NavObserver extends NavigatorObserver {
final navService = serviceLocator<NavigationService>();
@override
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
if (route.settings.name == "/") {
//initial route is provided by the app
navService.routeStack.add(AppRoute.Home);
} else {
navService.routeStack
.add(AppRoute.values[int.parse(route.settings.name)]);
}
}
@override
void didStopUserGesture() {}
@override
void didStartUserGesture(
Route<dynamic> route, Route<dynamic> previousRoute) {}
@override
void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) {}
@override
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) {
navService.routeStack.lastWhere((AppRoute appRoute) => route.settings.name == appRoute.index.toString());
}
@override
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
navService.routeStack.removeLast();
}
}
class Router {
final nav = serviceLocator<NavigationService>();
Route<dynamic> generateRoute(RouteSettings settings) {
final AppRoute appRoute = AppRoute.values[int.parse(settings.name)];
switch (appRoute) {
case AppRoute.AuthLogin:
return PageRouteBuilder(
settings: settings,
pageBuilder: (_, __, ___) =>
AuthScreen(dynamicLink: settings.arguments));
case AppRoute.AuthEmail:
return PageRouteBuilder(
settings: settings, pageBuilder: (_, __, ___) => EmailScreen());
case AppRoute.Home:
return PageRouteBuilder(
settings: settings, pageBuilder: (_, __, ___) => HomeScreen());
case AppRoute.Search:
return PageRouteBuilder(
settings: settings, pageBuilder: (_, __, ___) => SearchScreen());
case AppRoute.PublishGallery:
return PageRouteBuilder(
settings: settings,
pageBuilder: (_, __, ___) => PublishGalleryScreen());
case AppRoute.Notifications:
return PageRouteBuilder(
settings: settings,
pageBuilder: (_, __, ___) => NotificationsScreen());
case AppRoute.Profile:
return PageRouteBuilder(
settings: settings, pageBuilder: (_, __, ___) => ProfileScreen());
default:
//should never be called
return PageRouteBuilder(
pageBuilder: (_, __, ___) => Scaffold(
body: Center(
child: Text('No route defined for ${settings.name}')),
));
}
}
}
enum AppRoute {
AuthLogin,
AuthEmail,
Wizard,
Home,
Search,
PublishGallery,
Notifications,
Profile
}