Beautiful Snackbar on Flutter (without Scaffold) – Flushbar Library

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 {
  @override
  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 {
  @override
  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);

  @override
  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(
      // There is also a messageText property for when you want to
      // use a Text widget and not just a simple String
      message: 'Hello from a Flushbar',
      // Even the button can be styled to your heart's content
      mainButton: FlatButton(
        child: Text(
          'Click Me',
          style: TextStyle(color: Theme.of(context).accentColor),
        ),
        onPressed: () {},
      ),
      duration: Duration(seconds: 3),
      // Show it with a cascading operator
    )..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!

A Flushbar with an icon and additional color

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.

A Flushbar with all kinds of styling

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,
        ),
      ],
      // All of the previous Flushbars could be dismissed by swiping down
      // now we want to swipe to the sides
      dismissDirection: FlushbarDismissDirection.HORIZONTAL,
      // The default curve is Curves.easeOut
      forwardAnimationCurve: Curves.fastLinearToSlowEaseIn,
      title: 'This is a floating Flushbar',
      message: 'Lorem ipsum dolor sit amet',
    )..show(context);
  }

Conclusion

Even though Flutter provides its own Snackbar, using Flushbar is preferable in most cases. You can style every single bit of it and it also eliminates a lot of unnecessary boilerplate regarding the Scaffold.

If you want to show anything more than a simple message, Flushbar is a useful tool in your Flutter arsenal.

Snackbar icon made by Freepik from www.flaticon.com is licensed by CC 3.0 BY
Matej Rešetár
 

Matej is an app developer with a knack for teaching others. If he's not programming, making tutorials or doing other business, he's mostly working out, listening to audiobooks and taking cold showers.

>