从 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 Bar
的 onTap
回调我根据索引推送正确的名称路由。
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'));
我仍然不明白为什么 popUntil
到 PromotionsScreen
在使用 ModalRoute.withName
(与初始路由一起使用)时失败并且需要使用 route.settings.name
参数签入为了工作。
我在使用 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 Bar
的 onTap
回调我根据索引推送正确的名称路由。
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'));
我仍然不明白为什么 popUntil
到 PromotionsScreen
在使用 ModalRoute.withName
(与初始路由一起使用)时失败并且需要使用 route.settings.name
参数签入为了工作。