counter_animation_enhanced 1.0.4 copy "counter_animation_enhanced: ^1.0.4" to clipboard
counter_animation_enhanced: ^1.0.4 copied to clipboard

A rolling-digit counter for Flutter. Numbers count up and down on slot-machine wheels with spring motion, digit grouping, decimals and reduce-motion support.

counter_animation_enhanced #

A number that counts itself up — and down — on rolling digit wheels.

AnimatedCounter rolling its digits as the value counts up

AnimatedCounter puts every digit in a vertical column of ten faces. When the value changes, only the columns whose face actually changed turn; the rest hold perfectly still. So 1.00 → 1.01 rolls one wheel, 1.09 → 1.10 rolls two, and 999 → 1,000 slides a fresh column into place. The motion is a spring, not a tween, so a value that keeps changing re-aims the wheels that are already turning instead of queueing up a backlog behind them.

AnimatedCounter(
  value: 1234.5,
  decimals: 2,
  duration: const Duration(milliseconds: 800),
  prefix: const Text(r'$'),
  style: Theme.of(context).textTheme.displayMedium,
)

Why a wheel and not a crossfade #

Fading one digit into the next looks like the text being swapped out. A wheel turns, which is what the eye expects from a value that is increasing: the faces climb, and the digit you were reading leaves through the top. A short mask fade above and below each column lets that exit and entry read as movement rather than as two hard edges snapping past one another.

Features #

  • Spring motion. Position, arrival and turn all run on the same damped oscillator, tuned by duration and bounce.
  • Counts down as well as up. Wheels reverse and take the short way back; a wheel mid-turn is re-aimed, not restarted.
  • Fixed decimals, zero padding, and a sign column that only appears once there are digits to sign (-0.004 at two decimals shows 0.00, not -0.00).
  • Western, Indian and no digit grouping, with any separator characters: 1,234,567, 1.234.567, 12,34,567, or 1234567.
  • Prefix and suffix widgets so currency signs and units sit on the same line.
  • Reduce motion respected. The platform setting, or reduceMotion: true, holds every wheel still and jumps straight to the new number.
  • Accessible by construction. Screen readers get the value as plain text; the spinning wheels are decoration and are not read out.
  • Painted, not rebuilt. Digits are laid out once and drawn on a canvas, so a rolling value costs no per-frame text layout.

Getting started #

Add the package to pubspec.yaml:

dependencies:
  counter_animation_enhanced: ^1.0.0

Then import it:

import 'package:counter_animation_enhanced/counter_animation_enhanced.dart';

The counter inherits its font, size and colour from the surrounding DefaultTextStyle, so it drops into running text the way a Text widget would.

Usage #

Count to a new value #

The counter animates whenever value changes, so any state that rebuilds with a new number is enough:

AnimatedCounter(value: _seconds.toDouble() * 1000, duration: const Duration(seconds: 1))

Money, with decimals #

AnimatedCounter(
  value: 1234567.89,
  decimals: 2,
  separator: ',',
  prefix: const Text(r'$'),
)
// $1,234,567.89

Indian grouping #

AnimatedCounter(value: 12345678, grouping: CounterGrouping.indian)
// 1,23,45,678

A fixed-width readout #

padStart keeps a minimum number of whole digits on screen, so a timer or a score does not change width as it grows:

AnimatedCounter(value: 42, padStart: 5)
// 00042

Driving it from an animation #

Rebuild with an interpolated value; the wheels follow it frame by frame:

AnimatedBuilder(
  animation: controller,
  builder: (context, child) => AnimatedCounter(
    value: tween.evaluate(controller),
    duration: const Duration(milliseconds: 400),
  ),
)

Parameters #

Parameter Default Meaning
value required The number to show.
decimals 0 Digits after the decimal mark (0..15).
duration 600ms How long a wheel gets to settle.
padStart 1 Fewest whole digits shown (1..24).
separator , Group separator; '' for none.
decimalSeparator . Marker before the fractional part.
grouping western western, indian or none.
prefix/suffix null Widgets on either side of the number.
style inherited Merged over the ambient DefaultTextStyle.
lineHeight 1.5 Wheel height as a multiple of the font size.
bounce 0.18 Overshoot of the spring, 0 for none.
reduceMotion platform Forces the still layout on or off.
textDirection inherited Direction of the strip.

Formatting without the widget #

The formatting the wheels are built from is public too, so a plain-text label elsewhere on screen can match the counter exactly:

final shape = measureCounter(1234567.891, 2, 1, 0.6);
formatCounter(shape, ',', '.', CounterGrouping.western); // 1,234,567.89

Notes on edge cases #

  • NaN and Infinity are folded onto zero rather than printed.
  • Values are rounded to the nearest representable digit count; beyond 9,007,199,254,740,991 the low digits are noise, so they are held there.
  • A value that changes every frame is a stream of re-aims: the wheels keep turning towards wherever they are being sent, and always land on the face the final value asks for.
  • Digits use their font's own figures. For perfectly steady columns, pick a font with tabular figures (or a monospaced one); without them the column is sized by its widest face so the wheels still cannot shift each other sideways.

Example #

The example folder is a small app that counts a big number up from zero and shows the grouping, decimals, padding, sign and reduce-motion variants side by side. The clip above is that app running at the top of the page.

Additional information #

1
likes
155
points
409
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A rolling-digit counter for Flutter. Numbers count up and down on slot-machine wheels with spring motion, digit grouping, decimals and reduce-motion support.

Repository (GitHub)
View/report issues

Topics

#counter #animation #numbers #odometer #formatting

License

MIT (license)

Dependencies

flutter

More

Packages that depend on counter_animation_enhanced