从 Navigator Flutter 中正确弹出屏幕

Properly pop screens from Navigator Flutter

我在使用 Navigator.popUntil 返回到我需要返回的屏幕时遇到问题。

该应用程序是网页的一部分,Screen/Navigation 结构是: HomePage 推送 MainScreen(第一个应用程序屏幕),它使用导航栏在应用程序屏幕中导航,其中一个是 PromotionsScreen.

然后 PromotionScreen 使用 :

推送到 ChooseProductScreen
                                                  Navigator.push(
                                                    context,
                                                    MaterialPageRoute(
                                                      settings: RouteSettings(
                                                        name: 'PromotionsScreen'
                                                      ),
                                                      builder: (_) =>
                                                          BlocProvider.value(
                                                            value: BlocProvider.of<
                                                                PromotionBloc>(
                                                                context),
                                                            child: ChooseProductScreen(
                                                              user: widget.user,
                                                              cityDb: widget.cityDb,
                                                              regionDb: widget.regionDb,
                                                              countryDb: widget.countryDb,
                                                            ),
                                                          ),
                                                    ),
                                                  );

然后 ChooseProductScreen 使用 :

推送到 NewEditPromotionScreen
                                     Navigator.push(


                                     //  Navigator.pushReplacement( // Bloc event isn't sent from NewEditPromotionScreen


                                    context,
                                      MaterialPageRoute(
                                          settings: RouteSettings(
                                              name: 'ChooseProductScreen'
                                          ),
                                        builder: (_) =>
                                            BlocProvider.value(
                                              value: BlocProvider
                                                  .of<
                                                  PromotionBloc>(
                                                  context),
                                              child:
                                              NewEditPromotionScreen(
                                                  type: 'New',
                                                  user: widget
                                                      .user,
                                                  cityDb:
                                                  widget.cityDb,
                                                  regionDb: widget
                                                      .regionDb,
                                                  countryDb: widget
                                                      .countryDb),
                                            ),
                                      ),
                                    );

现在从 NewEditPromotionScreen 我想回到 PromotionsScreen:

// pop CircularProgressIndicator Dialog
                  Navigator.of(context, rootNavigator: true).pop(context);



                  // pop the screen
//                  Navigator.popUntil(context, (route) => route.isFirst); // pops to HomePage
//                  Navigator.popUntil(context, (route) => route.settings.name == 'PromotionsScreen'); // pops to white screen
//                  Navigator.popUntil(context, ModalRoute.withName('PromotionsScreen')); // pops only to ChooseProductScreen

                  Navigator.pushAndRemoveUntil(
                      context,
                      MaterialPageRoute(builder: (BuildContext context) => PromotionsScreen()), // Screen is not in NavigationBar 
                      (route) => false);

我试过了:

Navigator.popUntil(context, (route) => route.isFirst); 但是这会弹出网页 HomeScreen.

我尝试在推送到 ChooseProductScreen 时在 RouteSettings 中给 'PromotionsScreen ' 名称 PromotionsScreen,然后使用 Navigator.popUntil(context, ModalRoute.withName('PromotionsScreen')); 但只弹出直到 ChooseProductScreen.

这是因为'PromotionsScreen'是推送的路由名称 到 ChooseProductScreen 所以 popUntil 实际上按预期工作? 如果是这种情况,如何弹出到 PromotionsScreen 而不是因为它的路由由 NavigationBar 管理?

我也试过了:

Navigator.pushAndRemoveUntil(
                      context,
                      MaterialPageRoute(builder: (BuildContext context) => PromotionsScreen()),
                      (route) => false);

但这会显示导航栏中不存在的屏幕..

你能看出我在做什么吗?

非常感谢您的帮助。

尝试并实施自定义 Navigator,如此处接受的答案 .

所以我的 MainScreen 从将我的所有屏幕都放在列表中并使用索引处的屏幕作为正文,改为使用导航器的命名路由,并在 Navigation BaronTap回调我根据索引推送正确的名称路由。


Scaffold(
              key: _navigatorKey,
//              body: screens[_currentIndex],
            body: Navigator(
              key: _navigatorKey,
              initialRoute: '/',
              onGenerateRoute: (RouteSettings settings) {
                WidgetBuilder builder;
                // Manage your route names here
                switch (settings.name) {
                  case '/':
                    builder = (BuildContext context) => OrganizerScreen(
                      user: widget.user,
                      userLocation: widget.userLocation,
                      cityUser: widget.cityUser,
                      regionUser: widget.regionUser,
                      countryUser: widget.countryUser,
                      cityDb: widget.cityDb,
                      regionDb: widget.regionDb,
                      countryDb: widget.countryDb,
                    );
                    break;
                  case '/ProductsScreen':
                    builder = (BuildContext context) => ProductsScreen(
                      user: widget.user,
                      cityDb: widget.cityDb,
                      regionDb: widget.regionDb,
                      countryDb: widget.countryDb,
                    );
                    break;
                  case '/PromotionsScreen':
                    builder = (BuildContext context) => PromotionsScreen(
                      user: widget.user,
                      cityDb: widget.cityDb,
                      regionDb: widget.regionDb,
                      countryDb: widget.countryDb,
                    );
                    break;
                  case '/BookingScreen':
                    builder = (BuildContext context) => BookingScreen(
                      user: widget.user,
                      cityDb: widget.cityDb,
                      regionDb: widget.regionDb,
                      countryDb: widget.countryDb,
                    );
                    break;
                  case '/OrderScreen':
                    builder = (BuildContext context) => OrderScreen(
                      user: widget.user,
                      cityDb: widget.cityDb,
                      regionDb: widget.regionDb,
                      countryDb: widget.countryDb,
                    );
                    break;
                  case '/OpeningTimesScreen':
                    builder = (BuildContext context) => OpeningTimesScreen(
                      user: widget.user,
                      coordinates: widget.userLocation,
                      cityDb: widget.cityDb,
                      regionDb: widget.regionDb,
                      countryDb: widget.countryDb,
                    );
                    break;
                  case '/UserProfileScreen':
                    builder = (BuildContext context) => UserProfileScreen(
                      user: widget.user,
                      userLocation: widget.userLocation,
                      cityUser: widget.cityUser,
                      regionUser: widget.regionUser,
                      countryUser: widget.countryUser,
                    );
                    break;
                  default:
                    throw Exception('Invalid route: ${settings.name}');
                }
                // You can also return a PageRouteBuilder and
                // define custom transitions between pages
                return MaterialPageRoute(
                  builder: builder,
                  settings: settings,
                );
              },
            ),
              bottomNavigationBar: BottomNavigationBar(
                backgroundColor: Colors.transparent,
                showUnselectedLabels: true,
                unselectedItemColor: Colors.black38,
                selectedItemColor: Colors.orange,
//                onTap: onTabTapped,
                onTap: (int index) {
                  setState(() {
                    _currentIndex = index;

                    switch(index){
                      case 0:
                        _navigatorKey.currentState.pushNamed('/');
                        break;
                      case 1:
                        _navigatorKey.currentState.pushNamed('/ProductsScreen');
                        break;
                      case 2:
                        _navigatorKey.currentState.pushNamed('/PromotionsScreen');
                        break;
                      case 3:
                        _navigatorKey.currentState.pushNamed('/BookingScreen');
                        break;
                      case 4:
                        _navigatorKey.currentState.pushNamed('/OrderScreen');
                        break;
                      case 5:
                        _navigatorKey.currentState.pushNamed('/OpeningTimesScreen');
                        break;
                      case 6:
                        _navigatorKey.currentState.pushNamed('/UserProfileScreen');
                        break;
                      default:
                        throw Exception('Invalid route ');
                    }
                  });
                },
                currentIndex: _currentIndex,
                items: [
                  new BottomNavigationBarItem(
                    icon: Icon(Icons.calendar_today),
                    title: new AutoSizeText(
                      AppLocalizations.instance.text('Organizer'),
                      style: TextStyle(fontSize: 10, color: Colors.black54),
                      minFontSize: 5,
                      maxLines: 1,
                    ),
                  ),
                  new BottomNavigationBarItem(
                    icon: Icon(Icons.store), // .list),
                    title: new AutoSizeText(
                      AppLocalizations.instance.text('Shop'),
                      style: TextStyle(fontSize: 10, color: Colors.black54),
                      minFontSize: 5,
                      maxLines: 1,
                    ),
                  ),
                  new BottomNavigationBarItem(
                    icon: Icon(Icons.store), // .list),
                    title: new AutoSizeText(
                      AppLocalizations.instance.text('Promotions'),
                      style: TextStyle(fontSize: 10, color: Colors.black54),
                      minFontSize: 5,
                      maxLines: 1,
                    ),
                  ),
                  new BottomNavigationBarItem(
                    icon: new Icon(Icons.build),
                    title: new AutoSizeText(
                      AppLocalizations.instance.text('Bookings'),
                      style: TextStyle(fontSize: 10, color: Colors.black54),
                      minFontSize: 5,
                      maxLines: 1,
                    ),
                  ),
                  new BottomNavigationBarItem(
                    icon: new Icon(Icons.shopping_basket),
                    title: new AutoSizeText(
                      AppLocalizations.instance.text('Orders'),
                      style: TextStyle(fontSize: 10, color: Colors.black54),
                      minFontSize: 5,
                      maxLines: 1,
                    ),
                  ),
                  new BottomNavigationBarItem(
                    icon: Icon(Icons.access_time),
                    title: AutoSizeText(
                        AppLocalizations.instance.text('Opening Times'),
                        style: TextStyle(fontSize: 10, color: Colors.black54),
                        minFontSize: 5,
                        maxLines: 1),
                  ),
                  new BottomNavigationBarItem(
                    icon: Icon(Icons.person_outline),
                    title: AutoSizeText(
                        AppLocalizations.instance.text('User profile'),
                        style: TextStyle(fontSize: 10, color: Colors.black54),
                        minFontSize: 5,
                        maxLines: 1),
                  ),
//                  new BottomNavigationBarItem(
//                    icon: Icon(Icons.settings),
//                    title: AutoSizeText('Settings',
//                        style: TextStyle(fontSize: 10, color: Colors.black54),
//                        minFontSize: 5,
//                        maxLines: 1),
//                  ),
                ],
              ),

            ),

现在从 NewEditPromotionScreen 开始,我可以 pop 直到正确的路由名称是我需要的:


// working properly to go to PromotionsScreen :

Navigator.popUntil(context, (route) => route.settings.name == '/PromotionsScreen'); 

// or to initial route:

Navigator.popUntil(context, ModalRoute.withName('/'));



// Not working

Navigator.popUntil(context, ModalRoute.withName('/PromotionsScreen'));

// nor

Navigator.popUntil(context, ModalRoute.withName('PromotionsScreen'));

我仍然不明白为什么 popUntilPromotionsScreen 在使用 ModalRoute.withName(与初始路由一起使用)时失败并且需要使用 route.settings.name 参数签入为了工作。