fl_toast

A simple yet powerful Toast Library for Flutter

Features

✔️ Easy-to-use - Made for new and advanced developers
✔️ Animations - Supports any kind of animation
✔️ Made Fully in flutter - No need to use platform channels to show toasts
✔️ BuildContext is not necessary

Usage

context in all show toast methods are required and can't be null, otherwise an AssertionError is thrown.

Basic usage

import 'package:flutter_toast/flutter_toast.dart';

/// Shows a plaftform-styled toast with a text.
await showTextToast(
  text: 'My Awesome Toast',
  context: context,
);

Show the platform-styled toast

You can use showPlatformToast to show the toast that best fits the running platform. Shows an AndroidToast in Android and Fuchsia. Shows a StyledToast in the other platforms.

await showPlatformToast(
  child: Text('My Platform Toast'),
  context: context,
);
await showAndroidToast(
  child: Text('My awesome Android Toast'),
  context: context,
);

Multi-toasts

You can use showMultiToast to show multiple toasts at the same time.

await showMultiToast(
  toasts: [
    Toast(child: Text('Toast 1')),
    Toast(child: Text('Toast 2')),
  ],
  context: context,
);

You can use showSequencialToasts to show one toast after another. The duration of the toasts can NOT be null.

await showSequencialToasts(
  toasts: [
    Toast(child: Text('First toast'), duration: Duration(seconds: 2)),
    Toast(child: Text('Second toast'), duration: Duration(seconds: 1)),
  ],
  context: context,
);

Toast Provider

Ofter some people say: "I'd like to display toasts without context". Well, you can with ToastProvider. Just wrap your widgets in a ToastProvider and call ToastProvider.context in the context parameter:

MaterialApp(
  home: ToastProvider(child: Home()),
),
void displayToast() {
  showStyledToast(
    child: Text('Awesome styled toast'),
    context: ToastProvider.context,
  );
}

There must be an Overlay widget above ToastProvider. In the example above, the Overlay created by MaterialApp's Navigator is used.

Animations

You can highly customize the animation by setting animationBuilder. The default animation is a FadeTransition. The following snippet animate the toast with a scale transition.

await showStyledToast(
  child: Text('Styled toast with custom scale animation'),
  context: context,
  animationBuilder: (context, animation, child) {
    return ScaleTransition(
      scale: animation,
      child: child,
    );
  }
);

Flutter already has a set of pre-built transitions for you to use. They are:

  • FadeTransition (default)
  • ScaleTransition
  • SlideTransition
  • RotationTransition
  • SizeTransition
  • AlignTransition

You can combine multilpe transitions to build the best experience to the user:

await showPlatformToast(
  child: Text('Platform toast with multiple custom animations'),
  context: context,
  animationBuilder: (context, animation, child) {
    return ScaleTransition(
      scale: animation,
      child: RotationTransition(
        turns: animation,
        child: child,
      ),
    );
  }
);

You can even use the animations package. We're gonna be using FadeScaleTransition

import 'package:animations/animations.dart';

await showStyledToast(
  child: Text('Styled toast using animations package'),
  context: context,
  animationBuilder: (context, animation, child) {
    return FadeScaleTransition(
      animation: animation,
      child: child,
    );
  }
);

If none of the animations above have satisfied you, you can create your own implicit animations.

Cookbook

Learn how to create beautiful toasts.

Snackbar

The snippet below shows how to create a beautiful toast that act like a Snackbar. It's useful when you don't have a parent Scaffold avaiable to show a proper snackbar.

According to the Material Design Guidelines:

They (Snackbars) automatically disappear from the screen after a minimum of 4 (four) seconds, and a maximum of 10 (ten) seconds.

Snackbars can span the entire width of a UI. However, they should not appear in front of navigation or other important UI elements like floating action buttons.

showToast(
  interactive: true,
  padding: EdgeInsets.zero,
  alignment: Alignment(0, 1),
  /// The duration the toast will be on the screen
  duration: Duration(seconds: 4),
  /// The duration of the animation
  animationDuration: Duration(milliseconds: 200),
  /// Animate the toast to show up from the bottom 
  animationBuilder: (context, animation, child) {
    return SlideTransition(
      child: child,
      position: Tween<Offset>(
        begin: Offset(0, 1),
        end: Offset(0, 0),
      ).animate(CurvedAnimation(
        parent: animation,
        curve: Curves.fastOutSlowIn,
      )),
    );
  },
  child: Dismissible(
    key: ValueKey<String>('Snackbar'),
    direction: DismissDirection.down,
    child: Material(
      elevation: Theme.of(context)?.snackBarTheme?.elevation ?? 6.0,
      child: Container(
        width: double.infinity,
        padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
        color: Color(0xFF323232),
        child: Text('My Awesome Snackbar', style: TextStyle(color: Colors.white)),
      ),
    ),
  ),
  context: context,
);

Drawer

1. Create the ToastDrawer Widget.

It will be responsible by handling the dismiss color animation.

class ToastDrawer extends StatefulWidget {
  const ToastDrawer({
    Key key,
    @required this.onCloseRequested,
    @required this.content,
  }) : super(key: key);

  final Function onCloseRequested;
  final Widget content;

  @override
  _ToastDrawerState createState() => _ToastDrawerState();
}

class _ToastDrawerState extends State<ToastDrawer> {
  final key = GlobalKey<ToastState>();
  final animDuration = Duration(milliseconds: 246);
  Color backgroundColor = Colors.black54;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Positioned.fill(
          child: GestureDetector(
            onTap: () async {
              setState(() => backgroundColor = Colors.transparent);
              await key.currentState.dismissToastAnim();
              widget.onCloseRequested();
            },
            child: AnimatedContainer(
              duration: animDuration,
              curve: Curves.ease,
              color: backgroundColor,
            ),
          ),
        ),
        Positioned.fill(
          child: Toast(
            key: key,
            // Duration needs to be null, otherwise the toast will be in the screen
            // but the reverse animation will be called.
            duration: null,
            alignment: Alignment.topLeft,
            animationDuration: animDuration,
            animationBuilder: (context, animation, child) {
              return SlideTransition(
                position: Tween<Offset>(
                  begin: Offset(-1, 0),
                  end: Offset(0, 0),
                ).animate(CurvedAnimation(
                  parent: animation,
                  curve: Curves.ease,
                )),
                child: child,
              );
            },
            child: Dismissible(
              key: ValueKey(1),
              direction: DismissDirection.endToStart,
              onDismissed: (_) => widget.onCloseRequested(),
              child: Material(
                elevation: 8,
                child: Container(
                  width: MediaQuery.of(context).size.width * 0.75,
                  height: double.infinity,
                  // color: Colors.white,
                  child: widget.content,
                ),
              ),
            ),
          ),
        ),
      ],
    );
  }
}

2. Open the drawer

Open the drawer using a persistent toast. A persistent toast is a toast that will only dismiss when asked so.

Note: Don't forget to set duration: null in Toast, otherwise the toast will leave the screen but won't be dismissed

void openDrawer(Widget content) async {
  OverlayEntry entry;
  entry = showPersistentToast(
    context: context,
    toast: ToastDrawer(
      onCloseRequested: () => ToastManager.dismiss(entry),
      content: content,
    ),
  );
}

Advanced usage

Dismiss a toast programatically

To dismiss all the toasts in the screen, use ToastManager.dismissAll(). To dismiss a toast programatically, you can just call ToastManager.dismiss(entry). The only way to get the entry of a toast is to using showPersitentToast.

To dismiss with animation, you'll need a GlobalKey to access the toast state. The snippet below shows you how to do so:

final toastKey = GlobalKey<ToastState>();

final entry = showPersistentToast(
  context: context,
  toast: Toast(
    key: toastKey,
    duration: null,
  ),
);

Future.delayed(Duration(milliseconds: 250), () async {
  await toastKey.currentState?.dismissToastAnim();
  ToastManager.dismiss(entry);
});

Contribution

Feel free to open an issue if you find an error or make pull requests.

Apps using this library

Color Picker

Color picker is an app to help developers pick the best color that best suits their designs. You can pick colors from:

  • x Wheel
  • x Palette
  • x Value
  • x Named
  • x Image

TODO:

  • Add screenshots to the readme
  • Null-safety

Libraries

fl_toast