briankariuki/number_flow_flutter

GitHub: briankariuki/number_flow_flutter

一款 Flutter 动画数字组件,提供逐位滚动过渡、多格式化和丰富的动态视觉效果。

Stars: 7 | Forks: 0

# number_flow_flutter ![number_flow_flutter — 动画滚动数字演示](https://static.pigsec.cn/wp-content/uploads/repos/cas/a7/a70aee4bbd2a3b0606624063a243596293470198da898974762415a7f75eb75b.gif) 为 Flutter 提供精美的动画数字。当值发生变化时,每个数字都会像里程表一样滚动 到新位置 —— 具备区域感知格式化、随数字增加或减少的平滑 进入/退出过渡、可选的 iOS 风格弹簧效果,以及基于速度的动态模糊。 `NumberFlow` 处理数字(计数器、货币、百分比、紧凑和 科学计数法);`TimeFlow` 处理时钟、倒计时和秒表。 ## 功能 - **逐位滚动** —— 仅发生变化的数字会进行动画;其余数字 保持不动。 - **区域感知格式化** —— 支持十进制、货币、百分比、紧凑 (`1.2K`)、 科学 (`1.2×10³`) 和工程计数法,具备正确的分组、 数字系统以及 RTL。 - **平滑重排** —— 当数字增加或减少时,数字会滑动到新列,并且容器会调整大小; 进入的数字滚入,退出的数字淡出。 - **曲线或弹簧** —— 默认使用前置缓动曲线,或可选择启用 具有过冲和中断滚动时速度交接的类 iOS 弹簧效果。 - **动态模糊** —— 滚动时(垂直和/或水平)可选基于速度的模糊, 完全可调。 - **Scrub 模式** —— 从 `ValueListenable`(滑块、 图表 scrubber、手势)驱动显示,具有高刷新率且无需每次 tick 重新构建。 - **无障碍** —— 暴露纯文本语义标签;遵循平台 减弱动态效果设置。 ## 安装说明 添加到您的 `pubspec.yaml`: ``` dependencies: number_flow_flutter: ^0.0.1 ``` 然后: ``` import 'package:number_flow_flutter/number_flow_flutter.dart'; ``` ## 快速开始 ``` NumberFlow(value: 1234) ``` 就是这样 —— 每当重新构建时 `value` 发生变化,数字就会动画过渡到新的 数字。 ## NumberFlow ### 格式化 传递 `NumberFlowFormat` 来控制值的渲染方式: ``` // Currency NumberFlow( value: 1234.56, format: const NumberFlowFormat.currency(currencyCode: 'USD', symbol: r'$'), locale: 'en_US', ) // Percent (0.0–1.0 → 0%–100%) NumberFlow(value: 0.42, format: const NumberFlowFormat.percent()) // Compact — 1,234,567 → 1.2M NumberFlow( value: 1234567, format: const NumberFlowFormat.compact(maxFraction: 1), ) // Scientific — 12345 → 1.23×10⁴ (the exponent renders as a superscript) NumberFlow( value: 12345, format: const NumberFlowFormat.scientific(maxFraction: 2), ) // Engineering — exponent is always a multiple of 3 NumberFlow(value: 1500000, format: const NumberFlowFormat.engineering()) // Plain decimal with fraction bounds NumberFlow( value: 3.14159, format: const NumberFlowFormat.decimal(minFraction: 2, maxFraction: 2), ) ``` 每种格式都接受一个 `sign` (`SignDisplay.auto`、`always`、`exceptZero`、 `negative`、`never`) 来控制何时显示 `+`/`-` 号。 ### 前缀、后缀和趋势 ``` NumberFlow( value: score, prefix: '~', suffix: ' pts', // Direction the digits roll. Omit to auto-detect from the value change. trend: 1, // 1 up, -1 down, 0 shortest path ) ``` 如需自定义规则,请传递 `trendFn: (prev, next) => ...` 而不是 `trend`。 ### 样式和布局 ``` NumberFlow( value: 1234, style: const TextStyle(fontSize: 48, fontWeight: FontWeight.w600), textAlign: TextAlignValue.end, direction: Direction.auto, // ltr / rtl / auto tabularNums: true, // uniform digit width — no horizontal shift ) ``` ### 动画 默认情况下,滚动使用固定时长的缓动曲线。可以对其进行自定义,或者选择 启用弹簧效果: ``` // Custom curve timing NumberFlow( value: v, spinTiming: const TimingConfig( duration: Duration(milliseconds: 700), curve: NumberFlowCurve(), ), ) // iOS-like spring (overshoot + velocity hand-off on interrupt) NumberFlow(value: v, spring: NumberFlowSpring.ios) // Custom spring NumberFlow( value: v, spring: const NumberFlowSpring(mass: 1, stiffness: 170, damping: 20), ) ``` 其他动画参数: | 属性 | 描述 | | --- | --- | | `animated` | 主开关;为 `false` 时直接切换,无动画。 | | `respectMotionPreference` | 为 `true`(默认)时,遵循 OS 的减弱动态效果设置。 | | `transformTiming` | 水平重排的计时(数字滑动到新列)。 | | `opacityTiming` | 进入/退出淡入淡出的计时。 | | `continuous` | 里程表模式:在进位时未更改的低位数字会额外旋转一整圈(需要有方向的 `trend`)。 | | `stagger` | 每个数字从左到右的延迟(高位数字在前)。 | | `wheelSpacing` | 滚轮字形之间的垂直间距(× 行高)。 | | `mask` | 数字窗口的顶部/底部边缘淡出效果。 | ### 动态模糊和挤压 滚动较快时数字会发生模糊和压缩,然后在即将停止时恢复锐利并 弹回: ``` NumberFlow( value: v, motionBlur: 8, // max blur sigma (px) at peak speed motionBlurVelocityScale: 6, // lower = blur ramps in sooner / stronger motionBlurThreshold: 0.5, // roll speed below which no blur is applied digitSquish: 0.3, // horizontal squish: scaleX → 1 - 0.3 at peak ) ``` 模糊是对整个数字应用柔和的**磨砂**模糊,在快速滚动时会增强, 并在静止时完全消退变清晰 —— 因此只有移动的数字 才会模糊,已经静止的数字永远不会模糊。 `digitSquish` 在峰值速度时会将滚动数字水平压缩(至 `1 - digitSquish`), 并在其静止时弹回至全宽,从而产生一种干脆利落、 运动被压缩的感觉。它只影响实际正在移动的数字。 使用 `NumberFlowSpring.ios` 时,动态模糊、数字挤压和 stagger 都会自动 默认为 iOS 预设值 —— 显著的模糊(峰值 sigma 为 `4`,速度 缩放为 `4`)、`0.3` 的挤压以及从左到右的 stagger。传递显式值可以 覆盖其中任意一项。 ### 逐位限制 限制各个滚轮(例如,个位数只能在 0–5 之间变化的评分): ``` NumberFlow( value: rating, // position 0 = ones, 1 = tens, … digits: {0: const DigitConstraint(max: 5)}, ) ``` ### Scrub 模式 对于更新速度超过 widget 重新构建速度的值(滑块拖动、 图表 scrubber),可以通过 `ValueListenable` 驱动它。widget 每次 tick 都会重新格式化, 并且仅滚动发生变化的数字,除非数字位数发生变化,否则无需完全重新构建即可重绘: ``` final scrub = ValueNotifier(0); NumberFlow.scrub( value: scrub, format: const NumberFlowFormat.currency(currencyCode: 'USD', symbol: r'$'), tabularNums: true, // steady width for smooth scrubbing ) // later, from a gesture: scrub.value = newValue; ``` ## TimeFlow 动画时钟、倒计时或秒表。它是通过 prop 驱动的 —— 父级拥有 tick 的控制权(`Timer`、`Ticker` 或 stream)并推送新值。 ``` // Explicit fields TimeFlow(hours: 12, minutes: 30, seconds: 45) // From a Duration (countdown / stopwatch) TimeFlow.duration( elapsed, showHours: elapsed.inHours > 0, showCentiseconds: true, ) // From a DateTime (wall clock) TimeFlow.dateTime(DateTime.now(), showSeconds: true, is24Hour: false) ``` `TimeFlow` 接受与 `NumberFlow` 相同的动画属性 (`spinTiming`、`spring`、`motionBlur`、`wheelSpacing`、`mask` 等)。 ## 回调 两个 widget 都接受 `onAnimationsStart` 和 `onAnimationsFinish`: ``` NumberFlow( value: v, onAnimationsStart: () => debugPrint('rolling'), onAnimationsFinish: () => debugPrint('settled'), ) ``` ## 无障碍 每个 widget 都会暴露格式化后值的纯文本语义标签(例如 `"$1,234.56"`,科学计数法为 `"1.2E4"`),因此屏幕阅读器会读出 数字,而不是单独滚动的字形。当平台减弱动态效果 设置开启时,过渡会直接切换,而不是滚动(除非 `respectMotionPreference: false`)。 ## 示例 查看 [`example/`](example/) 应用以获取交互式图库:计数器、 货币、百分比、紧凑型、科学计数法、实时秒表、scrub 滑块,以及 针对每个动画参数的滑块。 ## 许可证 请参阅代码库中的 `LICENSE` 文件。
标签:Dart, Flutter, UI组件, 动画效果, 数字滚动, 移动开发