I have been using Navigator.pop and passing data back 1 screen with ease. However, if I use Navigator.popUntil, what is an acceptable way to pass an object back to the destination screen?
I have been using Navigator.pop and passing data back 1 screen with ease. However, if I use Navigator.popUntil, what is an acceptable way to pass an object back to the destination screen?
You can using arguments in RouteSettings to pass data back to a specific Route.
For example:
// in MaterialApp
MaterialApp(
onGenerateRoute: (settings) {
switch (settings.name) {
case '/':
return MaterialPageRoute(
settings: RouteSettings(name: '/', arguments: Map()), // (1)
builder: (_) => HomePage()
);
}
}
)
// in HomePage
Navigator.of(context).push(MaterialPageRoute(builder: (_) => StuffPage())
.then(_) {
final arguments = ModalRoute.of(context).settings.arguments as Map;
final result = arguments['result'];
};
// in StuffPage
Navigator.of(context).popUntil((route) {
if (route.settings.name == '/') {
(route.settings.arguments as Map)['result'] = 'something';
return true;
} else {
return false;
}
});
Note that: you have to initialize arguments or it will be null, that's what is the purpose of (1)
There is none. It also doesn't make sense because the result should be given back to the route that pushed the route.
If you really have to do this, use multiple pop calls:
// Widget of Route A:
String resultOfC = await Navigator.push(context, routeB);
// Widget of Route B:
String resultOfC = await Navigator.push<String>(context, routeC);
Navigator.pop(context, resultOfC); // pass result of C to A
// Widget of Route C:
Navigator.pop(context, 'my result'); // pass result to B
For workaround solution until the Flutter team provides it, you can do it using shared_preferences.
static const isBackFromPopUntil = "isBackFromPopUntil";
Future<void> saveIsBackFromPopUntil(bool isBack) async =>
await preferences.setBool(isBackFromPopUntil, isBack);
bool getIsBackFromPopUntil() =>
preferences.getBool(isBackFromPopUntil) ?? false;
popUntil, otherwise not. void _openBottomSheet(BuildContext context) async {
await showCupertinoModalBottomSheet(
context: context,
isDismissible: true,
...
);
final isBack = _prefHelper.getIsBackFromPopUntil();
if (isBack) {
// do stuff
await _prefHelper.saveIsBackFromPopUntil(false);
}
}
popUntil.void _popUntilDetailSavingPlan(BuildContext context) async {
final routeName = 'your name route that have bottom sheet (in the number 2 above)';
await _prefHelper.saveIsBackFromPopUntil(true);
Navigator.popUntil(context, ModalRoute.withName(routeName));
}
plus @hunghd answer's make sure that the screen settings that you will popback must not have a const key. otherwise you will be faced following error:
Unhandled Exception: Unsupported operation: Cannot modify unmodifiable map
I just removed the const key from settings on following code where the user will be popped back.
case HomeViewRoute:
return MaterialPageRoute(
builder: (context) => HomePage(),
settings: RouteSettings(name: HomeViewRoute, arguments: {}),
);