flutter_number_flow 0.1.0

SDKflutter
Platformandroidioswindowslinuxmacosweb

Animated Flutter widget for smooth number transitions. Perfect for counters, currency displays, and statistics with locale support.

Flutter Number Flow

pub package pub points likes license: MIT

A beautiful Flutter widget that animates number changes with smooth, customizable transitions. Perfect for displaying animated counters, currency values, statistics, and more with a professional, polished look.

✨ Features

  • 🎯 Smooth Number Animations: Animate only the digits that change, keeping unchanged digits stable
  • 🎨 Multiple Animation Styles: Choose between slide and crossFade animations for different visual effects
  • 🌍 Locale-Aware Formatting: Support for different locales, currencies, and number formats using intl
  • 📊 Compact Notation: Display large numbers in compact format (1.2K, 1.5M, 2.1B)
  • High Performance: Optimized with text metrics caching and tabular figures for consistent layout
  • 🎛️ Group Synchronization: Synchronize animations across multiple NumberFlow widgets
  • 🎮 Manual Control: Drive animations manually with scrub progress for timeline controls
  • Accessibility: Proper semantics support for screen readers
  • 🎭 Customizable: Full control over text styles, animation duration, and curves
  • 📱 Material 3: Built with Material Design 3 principles

📱 Demo

Mobile Demo
Mobile App
Web Demo
Web App

📱 Live Demo

Try the interactive web demo to see all features in action.

🚀 Quick Start

Installation

Add flutter_number_flow to your pubspec.yaml:

dependencies:
  flutter_number_flow: ^0.1.0

Then run:

flutter pub get

Basic Usage

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

class CounterExample extends StatefulWidget {
  @override
  _CounterExampleState createState() => _CounterExampleState();
}

class _CounterExampleState extends State<CounterExample> {
  double _value = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            NumberFlow(
              value: _value,
              textStyle: const TextStyle(
                fontSize: 48,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 32),
            ElevatedButton(
              onPressed: () => setState(() => _value += 1),
              child: const Text('Increment'),
            ),
          ],
        ),
      ),
    );
  }
}

🎨 Animation Styles

Slide Animation

Numbers slide vertically when changing, creating a smooth rolling effect:

NumberFlow(
  value: 1234.56,
  animationStyle: NumberFlowAnimation.slide,
  duration: const Duration(milliseconds: 600),
)

CrossFade Animation

Numbers fade between old and new values for a subtle transition:

NumberFlow(
  value: 1234.56,
  animationStyle: NumberFlowAnimation.crossFade,
  duration: const Duration(milliseconds: 400),
)

🌍 Formatting & Localization

Currency Formatting

NumberFlow(
  value: 1234.56,
  format: const NumberFlowFormat(
    prefix: '\$',
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  ),
  textStyle: const TextStyle(
    fontSize: 32,
    color: Colors.green,
    fontWeight: FontWeight.bold,
  ),
)

Compact Notation

Display large numbers in a readable format:

NumberFlow(
  value: 1500000,
  format: const NumberFlowFormat(
    notation: NumberNotation.compact,
    maximumFractionDigits: 1,
  ),
) // Displays "1.5M"

Locale Support

NumberFlow(
  value: 1234.56,
  format: const NumberFlowFormat(
    locale: 'de_DE', // German locale
    minimumFractionDigits: 2,
  ),
) // Displays "1.234,56"

🎛️ Advanced Features

Group Synchronization

Synchronize animations across multiple widgets:

NumberFlowGroupProvider(
  groupKey: 'financials',
  duration: const Duration(milliseconds: 800),
  child: Column(
    children: [
      NumberFlow(
        value: revenue,
        groupKey: 'financials',
        format: const NumberFlowFormat(prefix: '\$'),
      ),
      NumberFlow(
        value: expenses,
        groupKey: 'financials',
        format: const NumberFlowFormat(prefix: '\$'),
      ),
    ],
  ),
)

Manual Animation Control

Drive animations manually for timeline scrubbing:

class ScrubExample extends StatefulWidget {
  @override
  _ScrubExampleState createState() => _ScrubExampleState();
}

class _ScrubExampleState extends State<ScrubExample> {
  double _progress = 0.0;
  final double _startValue = 0;
  final double _endValue = 1000000;

  @override
  Widget build(BuildContext context) {
    final currentValue = _startValue + (_endValue - _startValue) * _progress;
    
    return Column(
      children: [
        NumberFlow(
          value: currentValue,
          scrubProgress: _progress,
          format: const NumberFlowFormat(
            prefix: '\$',
            notation: NumberNotation.compact,
          ),
        ),
        Slider(
          value: _progress,
          onChanged: (value) => setState(() => _progress = value),
        ),
      ],
    );
  }
}

📋 API Reference

NumberFlow Widget

PropertyTypeDefaultDescription
valuenumrequiredCurrent number value to display
previousValuenum?nullPrevious value for animation (auto-detected if null)
textStyleTextStyle?nullText style for the number display
animationStyleNumberFlowAnimationslideAnimation style (slide or crossFade)
durationDuration600msAnimation duration
curveCurveeaseInOutAnimation curve
formatNumberFlowFormat?nullNumber formatting options
textAlignTextAligncenterText alignment
groupKeyString?nullGroup key for synchronization
scrubProgressdouble?nullManual animation progress (0.0-1.0)
enableMaskbooltrueEnable edge masking for smooth clipping

NumberFlowFormat

PropertyTypeDefaultDescription
localeString?nullLocale for number formatting
notationNumberNotationstandardNumber notation (standard or compact)
prefixString?nullText to display before the number
suffixString?nullText to display after the number
minimumFractionDigitsint?nullMinimum decimal places
maximumFractionDigitsint?nullMaximum decimal places

NumberFlowAnimation

enum NumberFlowAnimation {
  slide,     // Vertical sliding animation
  crossFade, // Opacity transition animation
}

NumberNotation

enum NumberNotation {
  standard, // 1,234,567
  compact,  // 1.2M
}

🎯 Performance

Flutter Number Flow is optimized for performance:

  • Text Metrics Caching: Glyph dimensions are cached to avoid repeated calculations
  • Tabular Figures: Uses FontFeature.tabularFigures() for consistent digit widths
  • Efficient Diffing: Only animates digits that actually change
  • Minimal Rebuilds: Smart widget composition minimizes unnecessary rebuilds

♿ Accessibility

The widget follows Flutter accessibility best practices:

  • Semantic Labels: Screen readers announce the complete number value
  • Proper Focus: Supports keyboard navigation and focus management
  • High Contrast: Works well with system accessibility settings

🧪 Testing

The package includes comprehensive tests:

flutter test

Run golden tests to verify visual output:

flutter test --update-goldens

🤝 Contributing

Contributions are welcome! Please read our contributing guide and code of conduct.

Development Setup

  1. Clone the repository:

    git clone https://github.com/example/flutter_number_flow.git
    cd flutter_number_flow
    
  2. Get dependencies:

    flutter pub get
    
  3. Run the example:

    cd example
    flutter run
    
  4. Run tests:

    flutter test
    

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

📊 Changelog

See CHANGELOG.md for a detailed list of changes and migration guides.

💬 Support


Made with ❤️ by the Flutter Number Flow team