import React, { useEffect, useRef, useState } from 'react'; import { Animated, Easing, TextStyle } from 'react-native'; type AnimatedNumberProps = { value: number; // 最终值 durationMs?: number; format?: (v: number) => string; style?: TextStyle; /** 当该值变化时,从0重新动画 */ resetToken?: unknown; }; export function AnimatedNumber({ value, durationMs = 800, format, style, resetToken, }: AnimatedNumberProps) { const animated = useRef(new Animated.Value(0)).current; const [display, setDisplay] = useState('0'); useEffect(() => { animated.stopAnimation(() => { animated.setValue(0); Animated.timing(animated, { toValue: value, duration: durationMs, easing: Easing.out(Easing.cubic), useNativeDriver: false, }).start(); }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [value, resetToken]); useEffect(() => { const id = animated.addListener(({ value: v }) => { const num = Number(v) || 0; setDisplay(format ? format(num) : `${Math.round(num)}`); }); return () => animated.removeListener(id); }, [animated, format]); return {display}; }