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.

example/lib/main.dart

import 'dart:math' as math;

import 'package:counter_animation_enhanced/counter_animation_enhanced.dart';
import 'package:flutter/material.dart';

void main() => runApp(const CounterDemoApp());

/// The demo app: one big number counting up, and a few shapes of it below.
class CounterDemoApp extends StatelessWidget {
  /// Creates the demo app.
  const CounterDemoApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'AnimatedCounter demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorSchemeSeed: const Color(0xFF6C5CE7),
        useMaterial3: true,
      ),
      home: const CounterDemoPage(),
    );
  }
}

/// The demo page.
class CounterDemoPage extends StatefulWidget {
  /// Creates the demo page.
  const CounterDemoPage({super.key});

  @override
  State<CounterDemoPage> createState() => _CounterDemoPageState();
}

class _CounterDemoPageState extends State<CounterDemoPage>
    with SingleTickerProviderStateMixin {
  static const double _goal = 842197.32;

  late final AnimationController _runner = AnimationController(
    vsync: this,
    duration: const Duration(seconds: 4),
  );

  /// The value the big counter is asked to show, frame by frame.
  late final Animation<double> _amount = Tween<double>(
    begin: 0,
    end: _goal,
  ).animate(CurvedAnimation(parent: _runner, curve: Curves.easeOutCubic));

  /// Added by hand on top of whatever the driver is counting to, so a single
  /// step can be seen rolling one wheel.
  double _stepped = 0;

  @override
  void initState() {
    super.initState();
    _runner.forward();
  }

  @override
  void dispose() {
    _runner.dispose();
    super.dispose();
  }

  void _replay() {
    setState(() => _stepped = 0);
    _runner
      ..stop()
      ..value = 0
      ..forward();
  }

  @override
  Widget build(BuildContext context) {
    final ThemeData theme = Theme.of(context);
    return Scaffold(
      body: SafeArea(
        child: SingleChildScrollView(
          padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
          child: Center(
            child: ConstrainedBox(
              constraints: const BoxConstraints(maxWidth: 640),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Text('Counting up', style: theme.textTheme.titleMedium),
                  // Only the counter listens to the driver, so a frame costs no
                  // rebuild of anything else on the page.
                  AnimatedBuilder(
                    animation: _runner,
                    builder: (BuildContext context, Widget? child) {
                      return AnimatedCounter(
                        value: _amount.value + _stepped,
                        decimals: 2,
                        duration: const Duration(milliseconds: 400),
                        style: theme.textTheme.displayLarge!.copyWith(
                          fontWeight: FontWeight.w700,
                        ),
                      );
                    },
                  ),
                  const SizedBox(height: 16),
                  Wrap(
                    spacing: 8,
                    children: <Widget>[
                      FilledButton.icon(
                        onPressed: _replay,
                        icon: const Icon(Icons.replay),
                        label: const Text('Replay'),
                      ),
                      OutlinedButton(
                        onPressed: () => setState(() => _stepped += 1),
                        child: const Text('Step one'),
                      ),
                      OutlinedButton(
                        onPressed: () => setState(
                          () => _runner.value = math.Random().nextDouble(),
                        ),
                        child: const Text('Jump'),
                      ),
                    ],
                  ),
                  const SizedBox(height: 40),
                  Text('Shapes of it', style: theme.textTheme.titleMedium),
                  const SizedBox(height: 12),
                  const _ShapeRow(
                    label: 'Currency, no grouping',
                    child: AnimatedCounter(
                      value: 1234567,
                      separator: '',
                      prefix: Text(r'$'),
                    ),
                  ),
                  const _ShapeRow(
                    label: 'Lakhs and crores',
                    child: AnimatedCounter(
                      value: 12345678,
                      grouping: CounterGrouping.indian,
                    ),
                  ),
                  const _ShapeRow(
                    label: 'Percent, one decimal',
                    child: AnimatedCounter(
                      value: 99.9,
                      decimals: 1,
                      suffix: Text('%'),
                    ),
                  ),
                  const _ShapeRow(
                    label: 'Below zero',
                    child: AnimatedCounter(
                      value: -12.75,
                      decimals: 2,
                      suffix: Text('°C'),
                    ),
                  ),
                  const _ShapeRow(
                    label: 'Padded to five digits',
                    child: AnimatedCounter(value: 42, padStart: 5),
                  ),
                  const _ShapeRow(
                    label: 'Nothing moves under reduce motion',
                    child: AnimatedCounter(value: 987654, reduceMotion: true),
                  ),
                  const SizedBox(height: 24),
                  const _ChangeMyValue(),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

/// A label beside a counter.
class _ShapeRow extends StatelessWidget {
  const _ShapeRow({required this.label, required this.child});

  final String label;
  final Widget child;

  @override
  Widget build(BuildContext context) {
    final ThemeData theme = Theme.of(context);
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          SizedBox(
            width: 200,
            child: Text(
              label,
              style: theme.textTheme.bodyMedium?.copyWith(
                color: theme.colorScheme.onSurfaceVariant,
              ),
            ),
          ),
          Expanded(child: child),
        ],
      ),
    );
  }
}

/// A counter whose value is typed in, to show that any change rolls the wheels.
class _ChangeMyValue extends StatefulWidget {
  const _ChangeMyValue();

  @override
  State<_ChangeMyValue> createState() => _ChangeMyValueState();
}

class _ChangeMyValueState extends State<_ChangeMyValue> {
  double _value = 2026;

  @override
  Widget build(BuildContext context) {
    final ThemeData theme = Theme.of(context);
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Text('Your number', style: theme.textTheme.titleMedium),
        AnimatedCounter(
          value: _value,
          style: theme.textTheme.headlineMedium,
        ),
        Slider(
          min: -50000,
          max: 500000,
          value: _value.clamp(-50000, 500000),
          onChanged: (double value) => setState(() => _value = value),
        ),
      ],
    );
  }
}
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