Quick information messages, error messages, warning messages... Notifying users about certain actions is a must in the world of mobile apps. One of the best and the most streamlined ways of showing messages are snackbars. While Flutter provides an out-of-the-box solution, it's kind of clunky, styling it is hard if not impossible, you need to get hold of the Scaffold object which can sometimes create a lot of boilerplate code. Yes, Flutter's default snackbars are not all that great. All of these drawbacks can be solved with a light-weight library called Flushbar. You can style it to your heart's content and it's very simple to use.

Import the package

pubspec.yaml ... dependencies : flutter : sdk : flutter flushbar : ^1 .5 .0 ...

Showing snackbars This tutorial will take you through different examples of what you can do with a Snackbar. You can show a Snackbar from anywhere in the code. Before you learn about the Flushbar library, I feel it's good to know how to display the default Snackbar. Sometimes, you may not want to use a third-party package, and for simple messages, the default Snackbar might be just fine on some occasions. Flutter's default snackbar Showing the default Snackbar is actually a method on a Scaffold, and of course, you have to call it on the Scaffold instance of the "current page". Therefore, you have to obtain the Scaffold instance through an InheritedWidget - Scaffold.of(context).

main.dart class MyHomePage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text( 'Snackbar' )), body: Center( RaisedButton( child: Text( 'Show Default' ), onPressed: () => showDefaultSnackbar(context), ), ), ); } void showDefaultSnackbar(BuildContext context) { Scaffold.of(context).showSnackBar( SnackBar( content: Text( 'Hello from the default snackbar' ), action: SnackBarAction( label: 'Click Me' , onPressed: () {}, ), ), ); } }

Soooo, this will now work, right? Actually, the above code will not work in most cases. Now, showDefaultSnackbar is called from the RaisedButton. Unless ​this button is inside a nested widget (at least one level down the widget tree), you'll get an error saying "Scaffold.of() called with a context that does not contain a Scaffold". As I've said in the beginning, to circumvent this issue is to write some boilerplate - and who in their right mind wants to do that?!

main.dart class MyHomePage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text( 'Snackbar' )), body: Center( child: UselesslyNestedButton(), ), ); } } class UselesslyNestedButton extends StatelessWidget { const UselesslyNestedButton({ Key key, }) : super (key: key); Widget build(BuildContext context) { return RaisedButton( child: Text( 'Show Default' ), onPressed: () => showDefaultSnackbar(context), ); } void showDefaultSnackbar(BuildContext context) { Scaffold.of(context).showSnackBar( SnackBar( content: Text( 'Hello from the default snackbar' ), action: SnackBarAction( label: 'Click Me' , onPressed: () {}, ), ), ); } }

This, my friends, could be taught at schools as the definition of boilerplate. We had to move the button into a nested widget just to fulfill the requirements how the Scaffold's InheritedWidget works. There are also other ways to go around this problem, but still, you have to write extra code AND the Snackbar is still not very styleable.

Simple Flushbar

Flushbar sets out to solve all of the problems of the default Snackbar, together with adding the possibility to apply some pretty complex styling, if you want to. What follows is basically a copy of the default Snackbar using the Flushbar.

main.dart void showSimpleFlushbar(BuildContext context) { Flushbar( message: 'Hello from a Flushbar' , mainButton: FlatButton( child: Text( 'Click Me' , style: TextStyle(color: Theme.of(context).accentColor), ), onPressed: () {}, ), duration: Duration (seconds: 3 ), )..show(context); }

As you can see, there's no Scaffold, no boilerplate and it's totally styleable. You'll see how much you can style a Flushbar later in this tutorial.

Info Flushbar

Displaying only textual information is not enough. Many times, you want to differentiate between information, warning and error messages by using different colors and icons. With Flushbar, it's simple!

main.dart void showInfoFlushbar(BuildContext context) { Flushbar( title: 'This action is prohibited' , message: 'Lorem ipsum dolor sit amet' , icon: Icon( Icons.info_outline, size: 28 , color: Colors.blue.shade300, ), leftBarIndicatorColor: Colors.blue.shade300, duration: Duration (seconds: 3 ), )..show(context); }

Using Flushbar helpers

Displaying information, error or success messages is a pretty standard practice. For this reason, the author of the Flushbar library decided to include helpers. There are many of them and you can check them out at the official docs. Let's see how much shorter it is to recreate the above "info Flushbar" with a helper.

main.dart void showInfoFlushbarHelper(BuildContext context) { FlushbarHelper.createInformation( title: 'This action is prohibited' , message: 'Lorem ipsum dolor sit amet' , ).show(context); }

This is not bad at all! Especially when you're just prototyping, this code shortening will come in handy.

Going crazy with Flushbar

This awesome library doesn't end at information messages though. You really can go crazy with it. What follows is a rounded, floating Flushbar with gradient background, custom "arrival" animation and a shadow! However, Flushbar's customization doesn't stop there. There are many more properties to modify if you want to get even crazier.

main.dart void showFloatingFlushbar(BuildContext context) { Flushbar( aroundPadding: EdgeInsets.all( 10 ), borderRadius: 8 , backgroundGradient: LinearGradient( colors: [Colors.green.shade800, Colors.greenAccent.shade700], stops: [ 0.6 , 1 ], ), boxShadows: [ BoxShadow( color: Colors.black45, offset: Offset( 3 , 3 ), blurRadius: 3 , ), ], dismissDirection: FlushbarDismissDirection.HORIZONTAL, forwardAnimationCurve: Curves.fastLinearToSlowEaseIn, title: 'This is a floating Flushbar' , message: 'Lorem ipsum dolor sit amet' , )..show(context); }

Conclusion