Simple Close Button Handling for Flutter Snackbar

Adding a close button to a snackbar in Flutter is simple, however there is one subtlety to be aware of. If the view closes before the snackbar does then you can no longer get the ScaffoldMessenger from context in the close handler. Instead you need to pass the ScaffoldMessenger into the closure so that it remains available after the view closes.

Wrong Way

This approach will work most of the time, unless the view has already been disposed when the close button is clicked. Since snackbars are often used for errors or other termination handlers it is fairly common for the enclosing view to already be closed before the snackbar closes. If you try to access the ScaffoldMessengerState after closing the error is “Looking up a deactivated widget's ancestor is unsafe

var sn = scaffoldMessenger.showSnackBar(SnackBar(
  content: Container(
    child: Row(
      children: [
        IconButton(
            icon: Icon(Icons.close),
            onPressed: () {
              ScaffoldMessenger.of(context).hideCurrentSnackBar();
            }),
        Expanded(
          child: Text(
            'An important message',
          ),
        ),
      ],
    ),
  ),
  duration: Duration(seconds: 10),
));

Right Way

The only difference in this version is that the ScaffoldMessenger is retrieved outside of the closure for the close button handler. This continues to work whether or not the view that launched the snackbar has already closed.

var scaffoldMessenger = ScaffoldMessenger.of(context);
var sn = scaffoldMessenger.showSnackBar(SnackBar(
  content: Container(
    child: Row(
      children: [
        IconButton(
            icon: Icon(Icons.close),
            onPressed: () {
              scaffoldMessenger.hideCurrentSnackBar();
            }),
        Expanded(
          child: Text(
            'An important message',
          ),
        ),
      ],
    ),
  ),
  duration: Duration(seconds: 10),
));

Flutter Recommendation

In the dispose method of a widget snackbars should be removed by calling the removeCurrentSnackBar method if any snackbars might have been displayed by the Widget. This is good advice if the snackbar is only relevant to the context of the view. There may be cases where the notification should outlive the view to help explain why it is going away. I haven’t seen this cause problems but it’s worth considering.

ScaffoldMessengerState? _snackbarManager;

@override
void initState() {
  _snackbarManager = ScaffoldMessenger.of(context);
}

@override
void dispose() {
  _snackbarManager?.removeCurrentSnackBar();
}

Leave a Reply