Dependency-free text-roll animation for tiny, tactile UI labels — a Flutter port of slot-text.
Each character sits in its own clipped cell and changes by sliding: the new glyph enters from one side as the old slides out the other, staggered, with a springy overshoot so every letter lands with a little bounce.
import 'package:dart_slot_text/dart_slot_text.dart';
// Declarative — change `text` and it rolls.
SlotText(text: copied ? 'Copied' : 'Copy');The classic Copy → Copied → Copy in one call, with a controller:
final label = SlotTextController(initialText: 'Copy');
SlotText(controller: label);
// later, e.g. in onPressed:
label.flash('Copied', FlashOptions(
enter: SlotOptions(direction: SlotDirection.up, colorBuilder: chromatic()),
));| Method | What it does |
|---|---|
controller.set(text, options) |
Roll to new text — the text stays |
controller.flash(text, FlashOptions(...)) |
Roll in, then auto-revert |
controller.dispose() |
Clean up |
flash is spam-safe: repeat calls restart the revert timer instead of queuing
extra rolls, and an explicit set() cancels any pending revert.
| Option | Default | Description |
|---|---|---|
direction |
down |
Roll direction: up or down |
stagger |
45 |
Delay between characters (ms) |
duration |
300 |
Per-character animation time (ms) |
exitOffset |
50 |
Delay before the old character exits (ms) |
easing |
Cupertino spring | Animation curve (defaults to [SpringCurve]) |
bounce |
0.6 |
Per-letter overshoot / personality |
chromatic |
false |
One-line on/off for the built-in rainbow sweep |
color / colorBuilder |
— | Flat tint, or a per-character function |
colorFade |
280 |
Fade back to the resting color (ms) |
skipUnchanged |
true |
Don't re-roll identical characters |
interrupt |
true |
Cut off a roll in flight, or let it finish |
true(default) — a new roll cuts off any roll in flight, starts fresh.false— lets the current roll finish; the latest call plays after it lands, duplicates are dropped. Ideal for spam-prone buttons (flashuses this).
Rolls settle with a real Cupertino-style spring (SpringCurve, a damped
harmonic oscillator) instead of a fixed bezier. Tune the bounce:
SlotOptions(easing: SpringCurve(dampingRatio: 0.6)); // bouncier
SlotOptions(easing: SpringCurve(dampingRatio: 1.0)); // smooth, no overshootEach incoming glyph can roll in tinted, then fade back to the resting color
over colorFade ms. Flip it on with a single flag — no wiring needed:
SlotOptions(chromatic: on); // easy on/offFor full control, pass your own per-character function as colorBuilder (the
built-in chromatic() helper returns one), or a flat color. Precedence:
colorBuilder > chromatic: true > color.
For counters, prices and clocks, set tabularFigures: true on SlotText so every
digit takes the same width — the number won't shift sideways as digits change:
SlotText(controller: price, tabularFigures: true);It affects digits only; letters and punctuation are untouched.
- Each character animates in its own measured cell using your
style's exact font, so widths are always correct. - Tradeoffs inherent to per-character slot animation: kerning and ligatures are lost, joined scripts render isolated, ZWJ emoji split into cells. Ideal for short labels, numbers, statuses and commands.
See example/ for a runnable demo.
