'Flutter - Pass Data Back with .popUntil

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?



Solution 1:[1]

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)

Solution 2:[2]

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

Solution 3:[3]

For workaround solution until the Flutter team provides it, you can do it using shared_preferences.

  1. Add class with function to get and save value to shared_preferences.
  static const isBackFromPopUntil = "isBackFromPopUntil";

  Future<void> saveIsBackFromPopUntil(bool isBack) async =>
      await preferences.setBool(isBackFromPopUntil, isBack);

  bool getIsBackFromPopUntil() =>
      preferences.getBool(isBackFromPopUntil) ?? false;
  1. For example you need to check "someting" when modal bottom sheet is closed from 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);
    }
  }
  1. You back from the screen but using 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));
  }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 hunghd
Solution 2 boformer
Solution 3 R Rifa Fauzi Komara