Flutter: Remove all SnackBars

Viewed 2210

In my app, it is possible (and intended!) that multiple SnackBar elements are created. These SnackBar elements are queued and displayed one after another which is all well and fine. However, if I go to a different screen and then go back (so push and pop a route) all SnackBar elements are still there.

So I would like to remove all SnackBars upon pushing a route.

I tried counting my SnackBar elements and calling scaffoldKey.currentState.removeCurrentSnackBar() that many times in the following locations:

  • before Navigator.push() which works, however, since I have multiple points where I push something I would like to use some callback.

  • in didPushRoute() from WidgetsBindingObserver, however, even after registering the observer, this method is never called. (ChangeAppLifecycleState() is called so the registering seems to be not completely wrong?)

  • in dispose(). This actually produces my intended behavior but throws exceptions from AnimatedBuilder (Exception text: "setState() or markNeedsBuild() called during build."), which I would like to avoid, even if the animation library seems to catch those.

If everything fails, I suppose I could just wrap Navigator.push() in a helper function that also clears the SnackBar queue but I hoped that there would be a more elegant way.

3 Answers

You can use this to remove Snackbar in Flutetr2

ScaffoldMessenger.of(context).removeCurrentSnackBar();

Example code

onPressed: () {
    ScaffoldMessenger.of(context).removeCurrentSnackBar();
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('New Snackbar'),
      ),
    );
}

To clear all SnackBars, there is a ScaffoldMessenger.of(context).clearSnackBars() method which can be used in your pushNamed wrapper. :-)

So, in the end, I ended up writing the following function and call it everywhere instead of Navigator.pushNamed()

Future<T> _pushNamedWrapper<T extends Object>(
    BuildContext context,
    String routeName, {
    Object arguments,
  }) {
    for (int snackbarsLeft = _snackbarCounter;
        snackbarsLeft > 0;
        snackbarsLeft = snackbarsLeft - 1) {
      _scaffoldKey.currentState.removeCurrentSnackBar();
    }

    return Navigator.pushNamed(context, routeName, arguments: arguments);
  }

here, _snackbarCounter is a counter var that will be incremented whenever a snack bar is created or decremented as soon as it disappears. Roughly like this:

// function where you want your snackbar to be triggered
() { 
  _snackbarCounter = _snackbarCounter + 1;
  Scaffold.of(context)
    .showSnackBar(SnackBar(
      content: // your content...
    ))
    .closed
    .then((SnackBarClosedReason reason) =>
      _snackbarCounter = _snackbarCounter - 1);     
}
Related