animated_number_flow 0.1.0
animated_number_flow: ^0.1.0 copied to clipboard
A per-digit animated number ticker for Flutter. Only the digits that change roll, up for increases and down for decreases, with locale-free formatting.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:animated_number_flow/animated_number_flow.dart';
void main() => runApp(const DemoApp());
class DemoApp extends StatelessWidget {
const DemoApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'animated_number_flow',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorSchemeSeed: const Color(0xFF3949AB),
useMaterial3: true,
),
home: const DemoPage(),
);
}
}
class DemoPage extends StatefulWidget {
const DemoPage({super.key});
@override
State<DemoPage> createState() => _DemoPageState();
}
class _DemoPageState extends State<DemoPage> {
int _score = 1247;
double _price = 19.99;
Timer? _timer;
@override
void initState() {
super.initState();
_timer = Timer.periodic(const Duration(milliseconds: 900), (_) {
setState(() {
_score += 137;
_price += 3.5;
});
});
}
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Scaffold(
appBar: AppBar(title: const Text('animated_number_flow'), centerTitle: true),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Score', style: theme.textTheme.titleMedium),
const SizedBox(height: 8),
Center(
child: NumberFlow(
value: _score,
format: NumberFlowDefaults.thousandsLong(),
textStyle: theme.textTheme.displayMedium,
color: theme.colorScheme.primary,
),
),
const SizedBox(height: 32),
Text('Price', style: theme.textTheme.titleMedium),
const SizedBox(height: 8),
Center(
child: NumberFlow(
value: _price,
format: (v) =>
'\$${NumberFlowDefaults.thousands(decimalPlaces: 2)(v)}',
textStyle: theme.textTheme.displaySmall,
),
),
const SizedBox(height: 32),
Center(
child: FilledButton.tonal(
onPressed: () => setState(() {
_score = 1247;
_price = 19.99;
}),
child: const Text('Reset'),
),
),
],
),
),
),
);
}
}