Future of SnackBars – ScaffoldMessenger

Problem with current SnackBars:

  • To understand the need of ScaffoldMessenger, lets take an example of food ordering app. You added several items in cart, and you go on checkout screen. On checkout screen, you do the payment and click on some “Confirm Order” button, which will call some backend API to post these order details, and after this API call, you need to show some success message using SnackBar to the user that “Order placed successfully”, and also you want to take user to the order tracking screen.
  • Now here comes the problem, as current SnackBars would be shown by calling on the Scaffold within the current BuildContext.
  • By calling Scaffold.of(context).showSnackBar, the current Scaffold would animate a SnackBar into view. This would only apply to the current Scaffold, and would not persist across routes if they were changed in the course of the SnackBars presentation. This would also lead to errors if showSnackBar would be called in the course of executing an asynchronous event, and the BuildContext became invalidated by the route changing and the Scaffold being disposed of.

ScaffoldMessenger :

  • The ScaffoldMessenger now handles SnackBars in order to persist across routes and always be displayed on the current Scaffold. By default, a root ScaffoldMessenger is included in the MaterialApp, but you can create your own controlled scope for the ScaffoldMessenger to further control which Scaffolds receive your SnackBars.
  • When presenting a SnackBar during a transition, the SnackBar will complete a Hero animation, moving smoothly to the next page.
  • By using the ScaffoldMessenger, SnackBars can persist across multiple Scaffolds and transitions.

Benefits :

1. Persistent Snackbars
When you show a SnackBar on screen1, and before it times out if you change any route in the meantime and go to screen2, then also this SnackBar will be persisted as it is not managed by the Scaffold of the screen1 now, but is managed by the ScaffoldMessenger which is above in the hierarchy of both of your screens.

Image Courtesey: Taken from the example given by the Author of this widget (Kate Lovett)

2. Async Snackbars

Let’s say you click on a button on screen1, trigger some async event, move to screen2, and after the async event finishes, you want to show the result of that event using SnackBar. ScaffoldMessenger helps in achieving this kind of functionality.

Image Courtesey: Taken from the example given by the Author of this widget (Kate Lovett)

Example –

Kate Lovett, who is the author of this new widget has written a simple and easy to understand example of its usage.

import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => HomePage(),
'/second': (BuildContext context) => SecondPage(),
},
));
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: HomeBody(),
floatingActionButton: FloatingActionButton(
onPressed: () async {
ScaffoldMessengerState scaffoldMessenger = ScaffoldMessenger.of(context);
await Future.delayed(Duration(seconds: 5));
ScaffoldFeatureController controller = scaffoldMessenger.showSnackBar(
const SnackBar(content: Text('Snack-tastic')),
);
final result = await controller.closed;
print(result);
},
child: const Text('GO!'),
),
);
}
}
class HomeBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(child: Container()),
Padding(
padding: const EdgeInsets.all(16.0),
child: Text.rich(
TextSpan(
children:[
TextSpan(text: 'Pressing GO initiates\n'),
TextSpan(
text: 'ScaffoldMessenger.showSnackBar\n',
style: TextStyle(fontWeight: FontWeight.bold),
),
TextSpan(text: 'after a 5 second delay.'),
]
),
textAlign: TextAlign.center,
)
),
Container(height: 100),
RaisedButton(
child: Text('push Page 2'),
onPressed: () {
Navigator.of(context).pushNamed('/second');
},
),
Container(height: 50),
RaisedButton(
child: Text('popAndPush Page 2'),
onPressed: () {
Navigator.of(context).popAndPushNamed('/second');
},
),
Container(height: 50),
RaisedButton(
child: Text('pushReplacement Page 2'),
onPressed: () {
Navigator.of(context).pushReplacementNamed('/second');
},
),
Expanded(child: Container(), flex: 2),
],
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
bool canPop = ModalRoute.of(context)?.canPop ?? false;
return Scaffold(
appBar: AppBar(title: Text('Second')),
body: Center(child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Second Page'),
if (!canPop) RaisedButton(
child: Text('Start Over'),
onPressed: () {
Navigator.of(context).pushReplacementNamed('/');
},
)
],
))
);
}
}
view raw main.dart hosted with ❤ by GitHub

New APIs :

1. Show SnackBar – This adds SnackBar to the local SnackBar queue of each Scaffold, which is required as SnackBars need to be shown in the order they are pushed, one by one.

final ScaffoldMessengerState scaffoldMessenger = ScaffoldMessenger.of(context);
scaffoldMessenger.showSnackBar(
  const SnackBar(content: Text('Hello from ScaffoldMessenger')),
);

2. Hide SnackBar –

scaffoldMessenger.hideCurrentSnackBar();

3. Remove SnackBar –

scaffoldMessenger.removeCurrentSnackBar();

Deprecations :
Though previous way of showing SnackBars using Scaffold.of(context).showSnackBar() is not yet deprecated, the Flutter team does have plans to deprecate it and and then subsequently remove it sometime in the future.

Extensibility :
Flutter team is also planning to extend this for other notification widgets like showBottomSheet(), MaterialBanner() etc. and not just limit this for SnackBars.

Important note:
As of 19th November 2020, this is available till beta channel, and is not yet available in the stable channel.


References and credits :

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s