queued_toast 1.1.0
queued_toast: ^1.1.0 copied to clipboard
Overlay toasts for Flutter that queue per screen position, de-duplicate identical messages, stack up to five at a time and fade in and out.
queued_toast #
Overlay toasts for Flutter that queue per screen position, de-duplicate identical
messages, stack up to five at a time, and slide/fade in and out — all without a
BuildContext at the call site.
Queueing · the five styles · the three positions · dark mode
Features #
- Three positions —
top,centerandbottom, each with its own independent queue. - Adjustable edge offset —
offsetsets how far atoporbottomtoast sits from its edge, on top of the margin and safe area. - Automatic queueing — at most five toasts are visible per position (
Toast.maxVisible); the rest wait their turn. - De-duplication — a toast whose title and description match one already shown or queued is dropped.
- Five styles —
error,success,info,warningandminimal, each with a default icon and colour. - Light/dark theming —
ToastThemeresolves background, text and icon colours from the ambientThemebrightness. - Fully overridable per call — colours, icon, radius, elevation, padding, margin, max width, offset, and both durations.
- Readable by default — high-contrast surfaces, a hairline border, a blurred backdrop, and tuned type sizing, weight, tracking and line height.
- Interactive when you want it — tap and swipe to dismiss, plus an optional action button. A toast with no callbacks never steals a tap from the screen underneath.
- Dismissible by handle —
Toast.showreturns aToastHandlefor closing or inspecting that one toast. - Accessible — every toast is announced to screen readers, and the slide and fade are skipped when the platform asks to reduce motion.
- No third-party dependencies — nothing but Flutter itself.
Install #
dependencies:
queued_toast: ^1.1.0
Usage #
Toasts are rendered into the navigator's overlay, so the package needs your root navigator key once at startup:
import 'package:queued_toast/queued_toast.dart';
final navigatorKey = GlobalKey<NavigatorState>();
void main() {
Toast.init(navigatorKey: navigatorKey);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) =>
MaterialApp(navigatorKey: navigatorKey, home: const HomePage());
}
Then show a toast from anywhere — a bloc, a repository, a callback:
Toast.show(
title: 'Order filled',
description: '0.5 BTC at 64,120 USDT',
style: ToastStyle.success,
position: ToastPosition.top,
);
Toast.show throws if Toast.init has not been called.
Options #
| Parameter | Default | Description |
|---|---|---|
description |
required | Body text. |
title |
null |
Optional bold line above the description. |
style |
ToastStyle.minimal |
Picks the default background colour and icon. |
position |
ToastPosition.bottom |
Which queue the toast joins. |
duration |
2 s | How long the toast stays before reversing out. Duration.zero keeps it up until it is dismissed. |
animationDuration |
300 ms | Slide + fade in/out length. |
offset |
30% of screen height | Extra distance from the top or bottom edge, in logical pixels. Ignored at center. |
icon |
style default | Replaces the built-in icon entirely. |
iconSize |
20 | Size of the default icon. |
bgColor / textColor |
theme | Per-call colour overrides. |
borderRadius |
14 | Corner radius of the card. |
elevation |
6 | Material elevation. |
maxWidth |
420 | Widest the card grows before text wraps. |
maxLines |
null |
Lines the description may wrap onto before it ellipsizes. |
onTap |
null |
Called when the card is tapped. |
dismissOnTap |
false |
Whether a tap also dismisses the card. |
dismissOnSwipe |
false |
Whether a horizontal drag dismisses the card. |
actionLabel / onAction |
null |
Trailing button and its callback. The button dismisses the toast after running it. |
onDismissed |
null |
Called once the card has left the screen, however it went. |
padding |
EdgeInsets.symmetric(horizontal: 16, vertical: 12) |
Inside the card. |
margin |
EdgeInsets.all(12) |
Between the card and the screen edge. |
The offset is measured on top of margin and the safe area, and only the
offset of the oldest toast still on screen at a position is applied — one
position is one stack:
Toast.show(
description: 'Pinned 24px above the bottom edge',
position: ToastPosition.bottom,
offset: 24,
);
Dismissing and interaction #
Toast.show returns a ToastHandle for the toast it raised:
final handle = Toast.show(
description: 'Uploading…',
duration: Duration.zero, // stays until something dismisses it
);
await upload();
handle.dismiss();
Toasts can also be tapped, swiped away, or carry an action button:
Toast.show(
title: 'Message archived',
description: 'Moved to All Mail',
actionLabel: 'Undo',
onAction: restore,
dismissOnSwipe: true,
onDismissed: () => log('gone'),
);
A toast with none of onTap, dismissOnTap, dismissOnSwipe or onAction is
wrapped in an IgnorePointer, so it never blocks the screen underneath.
To control the stacks themselves:
Toast.maxVisible = 3; // cap per position
Toast.dismissAll(position: ToastPosition.top); // animate a stack out
Toast.reset(); // clear everything at once
Toast.visibleCount(), Toast.queuedCount(); // inspect a stack
Theming #
Pass a ToastTheme to Toast.init to restyle every toast at once:
Toast.init(
navigatorKey: navigatorKey,
theme: ToastTheme(
lightBackgroundColors: {ToastStyle.success: Colors.teal.shade700},
darkBackgroundColors: {ToastStyle.success: Colors.teal.shade900},
fontFamily: 'Inter',
titleFontSize: 15,
titleFontWeight: FontWeight.w600,
descriptionFontSize: 13.5,
descriptionOpacity: 0.88,
),
);
Typography is tunable beyond size: titleFontWeight, titleLetterSpacing,
titleHeight, descriptionFontWeight, descriptionLetterSpacing,
descriptionHeight and descriptionOpacity all have defaults tuned for small
overlay text, and fontFamily swaps the face for both lines. lightBorderColor
and darkBorderColor control the hairline around the card.
ToastTheme.copyWith merges background-colour overrides into the existing maps
rather than replacing them, so you can tweak a single style and keep the rest.
Regenerating the screenshots #
The images above are rendered headlessly, so they stay in step with the code:
flutter test tool/generate_media.dart --update-goldens && python3 tool/assemble_gif.py
The first command writes the stills into screenshots/ and the GIF's frames
into build/gif_frames/; the second encodes those frames into
screenshots/queue.gif (needs Pillow). Neither tool/ nor build/ ships with
the package.
License #
MIT — see LICENSE.
