Как убрать всплывающие экраны во флаттере с помощью навигатора 2.0
Я использую navigator 2.0 и Provider для добавления и удаления экранов. когда я перемещаюсь с помощью Drawer(), я могу перейти с первого экрана на второй экран, но не обратно... таким образом, выбрав пункт меню в ящике. Ошибка, которую я получаю, заключается в следующем:
_AssertionError ('package:flutter/src/widgets/navigator.dart': Failed assertion: line 3470 pos 18: '!keyReservation.contains(key)': is not true.) The relevant error-causing widget was Router<dynamic>
. Однако нажатие кнопки «Назад» на телефоне работает.
Я хотел знать, как я могу удалить первый экран, например, перед переходом на второй экран, или каким-либо образом обойти это.
вот мой код роутера:
class AppRouter extends RouterDelegate
with ChangeNotifier, PopNavigatorRouterDelegateMixin {
@override
// navigatorKey
final GlobalKey<NavigatorState> navigatorKey;
// Screen Managers
final AppStateManager appStateManager;
final ProjectsScreenManager projectScreenManager;
AppRouter({
// initialize all the screen managers
required this.appStateManager,
required this.projectScreenManager,
}) : navigatorKey = GlobalKey<NavigatorState>() {
// add Listerners for all the state managers
appStateManager.addListener(notifyListeners);
projectScreenManager.addListener(notifyListeners);
}
// Dipose all managers after use
@override
void dispose() {
appStateManager.removeListener(notifyListeners);
projectScreenManager.removeListener(notifyListeners);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Navigator(
key: navigatorKey,
onPopPage: _handlePopPage,
pages: [
// A list of Pages & their Conditions
if (!appStateManager.isInitialized) SplashScreen.page(),
if (appStateManager.isInitialized) HomeScreen.page(),
if (appStateManager.goToProjects) ProjectsScreen.page(),
if (projectScreenManager.gotToProjectDetails)
ProjectDetailsScreen.page(),
if (appStateManager.goToDashboard) HomeScreen.page(),
if (appStateManager.goToTasks) TasksScreen.page(),
],
);
}
bool _handlePopPage(Route route, result) {
// Checks if the current route’s pop succeeded
// If it failed, return false; ELSE checks the different routes and
// triggers the appropriate state changes
if (!route.didPop(result)) {
return false;
}
// Handle States when user closes a screen
if (route.settings.name == KaizenPages.projectsScreenPath) {
appStateManager.setgoToProjects(false);
}
if (route.settings.name == KaizenPages.projectDetailsScreenPath) {
projectScreenManager.goToProjectDetails(false);
}
if (route.settings.name == KaizenPages.homePath) {
appStateManager.setgoToDashboard(false);
}
if (route.settings.name == KaizenPages.tasksScreenPath) {
appStateManager.setgoToTasks(false);
}
return true;
}
@override
Future<void> setNewRoutePath(configuration) async => null;
}
Вот провайдер:
class AppStateManager extends BaseScreenProvider {
// variables ....Fields
bool _initialized = false;
NavigationItem _navigationItem = NavigationItem.dashboard;
bool _goToProjects = false;
bool _goToDashboard = false;
bool _goToTasks = false;
// Getter Methods
bool get isInitialized => _initialized;
bool get goToProjects => _goToProjects;
bool get goToTasks => _goToTasks;
NavigationItem get getNavItem => _navigationItem;
bool get goToDashboard => _goToDashboard;
// initializeApp Method
void initializeApp() {
Timer(const Duration(milliseconds: 2000), () {
_initialized = true;
notifyListeners();
});
}
void setgoToProjects(bool goToProjects) {
_goToProjects = goToProjects;
notifyListeners();
}
void setgoToTasks(bool goToTasks) {
_goToTasks = goToTasks;
notifyListeners();
}
// Go to dashboard Screen
void setgoToDashboard(bool goToDashboard) {
_goToDashboard = goToDashboard;
notifyListeners();
}
// set nav item
void setNavItem(NavigationItem navigationItem) {
_navigationItem = navigationItem;
notifyListeners();
}
}
Внутри виджета Drawer у меня есть этот код, который отображает пункты меню в ящике
//...other widget here....
// Menu Contents|List
SingleChildScrollView(
child: Container(
padding: padding,
child: Column(
children: [
// ...other item removed
// List Tiles
buildMenuItem(
text: "Dashboard",
icon: Icons.home_outlined,
onClicked: () async {
// Navigate to dashboard screen
locator<AppStateManager>().setgoToDashboard(true);
locator<AppStateManager>()
.setNavItem(NavigationItem.dashboard);
},
context: context,
navigationItem: NavigationItem.dashboard,
),
buildMenuItem(
text: "Projects",
icon: Icons.view_stream,
onClicked: () {
locator<AppStateManager>().setgoToProjects(true);
locator<AppStateManager>()
.setNavItem(NavigationItem.projects);
},
context: context,
navigationItem: NavigationItem.projects,
),
buildMenuItem(
text: "Tasks",
icon: Icons.fact_check,
onClicked: () {
locator<AppStateManager>().setgoToTasks(true);
Navigator.pop(context);
locator<AppStateManager>().setNavItem(NavigationItem.tasks);
},
context: context,
navigationItem: NavigationItem.tasks,
),
),
],
),
),
)
виджет buildMenuItem
// List Item| Tile
Widget buildMenuItem({
required String text,
required IconData icon,
VoidCallback? onClicked,
required NavigationItem navigationItem,
required context,
}) {
final currentItem = locator<AppStateManager>().getNavItem;
final isSelected = navigationItem == currentItem;
final color = isSelected ? kaizenOrange : Theme.of(context).iconTheme.color;
return Material(
child: ListTile(
leading: Icon(
icon,
color: color,
),
title: Text(
text,
style: Theme.of(context).textTheme.bodyText2!.copyWith(color: color),
),
onTap: onClicked,
),
);
}
locator() - это просто пакет внедрения зависимостей для использования/внедрения провайдеров... вот его настройка
import 'package:get_it/get_it.dart';
GetIt locator = GetIt.instance;
void setupLocator() {
// Register Services here (API/AuthService/...)
locator.registerLazySingleton(() => KaizenMockAPI());
// Register screen/model Providers here
locator.registerLazySingleton(() => AppStateManager());
locator.registerLazySingleton(() => ProjectsScreenManager());
locator.registerLazySingleton(() => TasksScreenManager());
}
вот как я использую Router в моем main.dart
class _KaizenAppState extends State<KaizenApp> {
// Hold all the state managers here ...
final _appStateManager = locator<AppStateManager>();
final _projectScreenStateManager = locator<ProjectsScreenManager>();
// appRouter here Nav2.0
late AppRouter _appRouter;
@override
void initState() {
_appRouter = AppRouter(appStateManager: _appStateManager, projectScreenManager: _projectScreenStateManager);
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: _theme,
),
home: Router(
routerDelegate: _appRouter,
backButtonDispatcher: RootBackButtonDispatcher(),
),
debugShowCheckedModeBanner: false,
);
}
}