How To Create Toast In Flutter

In this post we will learn to create Toast in Flutter. We create a wrapper class which can be used to load Toast anywhere within your Flutter application.

Introduction

In Android, a toast is a mechanism to show feedback for the user.

Android Toast
Android Toast

The feedback is usually a short message which occupies a small area which disappears after a small interval of time.

DecisionMentor app

In Flutter, we do not have a widget which is equivalent of Toast. So, here we will learn to build a Toast widget in Flutter with the help of a special widget called Overlay and some Animations.

Setup

In order to build a Toast, we will need to do some ground work first. The whole process of building a Toast in Flutter will look something like this:

  • Build an animation for bringing Toast in and out of existence. We will be using AnimatedOpacity widget for this purpose.
  • Next, we will add the animation as a part of an Overlay widget so that it can appear on top of any widgets.
  • Finally, we will build a wrapper function to easily load Toast by passing message, colors etc. as parameters.

Setup AnimatedOpacity

Let’s start by setting up the AnimatedOpacity first.

The AnimatedOpacity basically works by changing the opacity of a widget from 0.0 to 1.0. If the opacity is 0.0 it is invisible and the closer it gets towards 1.0, the more visible it becomes.

AnimatedOpacity widget achieves this without having to specify any animation explicitly.

So, let’s create a wrapper class _ToastAnimatedWidget for the AnimatedOpacity widget.

class _ToastAnimatedWidget extends StatefulWidget {
  _ToastAnimatedWidget({
    Key key,
    @required this.child,
  }) : super(key: key);

  final Widget child;
  
  @override
  _ToastWidgetState createState() => _ToastWidgetState();
}

class _ToastWidgetState extends State<_ToastAnimatedWidget>
    with SingleTickerProviderStateMixin {

  bool get _isVisible => true; //update this value later
  
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Positioned(
      bottom: 50,
      child: AnimatedOpacity(
        duration: Duration(seconds: 2),
        opacity: _isVisible ? 1.0 : 0.0,
        child: widget.child,
      )
    );
  }
}

Here, _ToastAnimatedWidget is a private Stateful widget which takes a child widget and builds it as a child of AnimatedOpacity widget. Since we want the Toast to be positioned towards the the bottom area of device, we have wrapped it around Positioned widget.

The _isVisible value decides the opacity for the child widget. We will update the initiation of this value later.

Setup Overlay For Toast

Overlay is a useful widget which allows us to add floating widgets in our app. Imagine one widget floating on top of another; exactly serves the use case of creating toast message.

The items in Overlay are Stack of entries.

When working with Overlay, we first need to get access to the current state of the Overlay for the app. Then add entries to the Stack.

var overlayState = Overlay.of(context);
overlayState.insert(OverlayEntry(...));

Each entry of the Overlay widget is called an OverlayEntry. The entry requires a WidgetBuilder for building the child entry.

We will build our _ToastAnimatedWidget as the child OverlayEntry with the help of builder.

So, let’s create another class Toast which will be responsible for adding and removing toast message to the Overlay.

Complete Implementation To Create Toast In Flutter

Create Toast Class

Here’s the complete implementation for Toast class.

class Toast {
  static void show(
    String msg,
    BuildContext context, {
    Color backgroundColor = const Color.fromRGBO(0, 0, 0, 0.6),
    Color textColor = Colors.white,
  }) {
    dismiss();
    Toast._createView(
        msg, context, backgroundColor, textColor);
  }

  static OverlayEntry _overlayEntry;
  static bool isVisible = false;

  static void _createView(
    String msg, 
    BuildContext context, 
    Color background,
    Color textColor, 
  ) async {
    var overlayState = Overlay.of(context);

    final themeData = Theme.of(context);

    _overlayEntry = new OverlayEntry(
      builder: (BuildContext context) => _ToastAnimatedWidget(
        child: Container(
          width: MediaQuery.of(context).size.width,
          child: Container(
            alignment: Alignment.center,
            width: MediaQuery.of(context).size.width,
            child: Container(
              decoration: BoxDecoration(
                color: background,
                borderRadius: BorderRadius.circular(20),
              ),
              margin: EdgeInsets.symmetric(horizontal: 20),
              padding: EdgeInsets.fromLTRB(16, 10, 16, 10),
              child: Text(
                msg,
                softWrap: true,
                style: themeData.textTheme.body1.copyWith(
                  fontFamily: 'Lato',
                  color: Colors.white,
                ),
              ),
            ),
          ),
        ),
      ),
    );
    isVisible = true;
    overlayState.insert(_overlayEntry);
  }

  static dismiss() async {
    if (!isVisible) {
      return;
    }
    isVisible = false;
    _overlayEntry?.remove();
  }
}

The _createView method is responsible for adding entries to the Overlay stack and the dismiss method removes the entries.

The static method show is the main wrapper which can be called from anywhere in the app to show toast messages.

Next, we need to tweak the _ToastWidgetState class a little.

Tweak _ToastWidgetState Class

class _ToastWidgetState extends State<_ToastAnimatedWidget>
    with SingleTickerProviderStateMixin {
  bool get _isVisible => Toast.isVisible;

  @override
  void initState() {
    super.initState();

    WidgetsBinding.instance.addPostFrameCallback((context) {
      if (this.mounted) {
        Future.delayed(Duration(seconds: 2), () {
          Toast.dismiss();
        });
      }
    });
  }
...
.

The _isVisible field gets updated based on the Toast isVisible value.

Another important thing is that we have added a addPostFrameCallback. The callback gets called after the build function has been called. This gives us an opportunity to remove the OverlayEntry from the Stack.

Implement Toast Class

Now that we have completed all the setup part, it’s time to put things into action!

You can now load the toast message from anywhere within your Flutter app by calling Toast.show static method.

FlatButton(
	child: Text('Toast It!'),
	onPressed: () {
	  Toast.show('Showing a toast..', context, backgroundColor: Colors.green);
	},
  ),

Wrapping Up

In this post we learnt to build a Toast message widget in Flutter app from scratch. We also learnt to use interesting widgets like AnimatedOpacity and Overlay.

If you would enjoyed this article and would like to learn more, do check out our other articles on Flutter and Dart.