Vincenzo
Vincenzo

Reputation: 6358

Properly pop screens from Navigator Flutter

I'm having troubles using Navigator.popUntil to go back to the screen I need to go back to.

The app is part of a Web page and Screen/Navigation structure is : HomePage pushes MainScreen(first app screen) that uses a Navigation bar to navigate through app's screens, one of which is PromotionsScreen.

Then PromotionScreen pushes to ChooseProductScreen with :

                                                  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,
                                                            ),
                                                          ),
                                                    ),
                                                  );

Then ChooseProductScreen pushes to NewEditPromotionScreen with :

                                     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),
                                            ),
                                      ),
                                    );

Now from NewEditPromotionScreen I want to go back to 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);

I tried:

Navigator.popUntil(context, (route) => route.isFirst); but this will pop to the web page HomeScreen.

I tried giving a 'PromotionsScreen ' name in RouteSettings in PromotionsScreen when pushing to ChooseProductScreen, and then using Navigator.popUntil(context, ModalRoute.withName('PromotionsScreen')); but pops only until ChooseProductScreen.

Is this because 'PromotionsScreen' is the name of the route that pushes to ChooseProductScreen so popUntil is actually working as expected? If this is the case how can pop to PromotionsScreen instead as the route to it is managed by the NavigationBar?

I also tried :

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

but this would present the screen not in the navigation bar..

Can you spot what I'm doing worn using either way?

Many thanks for the help.

Upvotes: 2

Views: 1363

Answers (1)

Vincenzo
Vincenzo

Reputation: 6358

Tried and implemented a custom Navigator as in the accepted answer here Flutter persistent navigation bar with named routes?.

So my MainScreen changed from having all my Screens in List and using the one at index as the body, to using the Navigator's named routes instead and in the Navigation Bar's onTap callback I push the proper name route depending on the index.


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),
//                  ),
                ],
              ),

            ),

Now from NewEditPromotionScreen I can pop until the proper route name is the one I need:


// 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'));

Still I don't understand why popUntil to PromotionsScreen fails when using ModalRoute.withName (which works with initial route) and needs to use route.settings.name parameter check in order to work.

Upvotes: 1

Related Questions