Reputation: 6358
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);
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
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