Поставьте зависимости:
npm install @react-native-masked-view/masked-view expo-blur expo-linear-gradient react-native-reanimated react-native-workletspnpm add @react-native-masked-view/masked-view expo-blur expo-linear-gradient react-native-reanimated react-native-workletsyarn add @react-native-masked-view/masked-view expo-blur expo-linear-gradient react-native-reanimated react-native-workletsbun add @react-native-masked-view/masked-view expo-blur expo-linear-gradient react-native-reanimated react-native-workletsСкопируйте эти файлы в src/shared/components/organisms/rolling-counter/:
Проверьте алиас путей. Импорты в коде выше записаны так, как их пишет astra-rn add: @/shared/components, @/shared/utils и @/shared/hooks. Нужен алиас "@/*": ["./src/*"] в tsconfig.json — или поправьте импорты под свои пути.
import React from "react";
import { Pressable, StyleSheet, Text, View } from "react-native";
import { useSharedValue, Easing } from "react-native-reanimated";
import { RollingCounter } from "@/shared/components/organisms/rolling-counter";
import { Showcase, useAutoplay, useCustomize } from "~/showcase";
const CUSTOMIZE = [
{ key: "color", label: "Цвет цифр", type: "color", default: "#ffffff" },
{ key: "fontSize", label: "Размер шрифта", type: "slider", min: 20, max: 96, step: 1, unit: "px", default: 58 },
{ key: "height", label: "Высота цифры", type: "slider", min: 30, max: 120, step: 1, unit: "px", default: 72 },
{ key: "width", label: "Ширина цифры", type: "slider", min: 20, max: 80, step: 1, unit: "px", default: 46 },
{ key: "duration", label: "Длительность", type: "slider", min: 100, max: 2500, step: 50, unit: "ms", default: 900 },
{ key: "stagger", label: "Задержка разрядов", type: "slider", min: 0, max: 150, step: 1, unit: "ms", default: 38 },
{ key: "fadeEdges", label: "Затухание краёв", type: "toggle", default: true },
{ key: "motionBlur", label: "Размытие движения", type: "toggle", default: true },
] as const;
const AUTOPLAY_STEPS: [(value: number) => number, number][] = [
[(value) => value + 1, 230],
[(value) => value + 1, 230],
[(value) => value + 1, 230],
[(value) => value + 1, 230],
[(value) => value + 1, 230],
[(value) => value + 1, 330],
[(value) => value + 111, 680],
[() => 3562, 560],
[() => 2145, 300],
[() => 1933, 620],
[(value) => value + 1, 250],
[(value) => value + 1, 250],
[(value) => value + 1, 250],
[(value) => value + 1, 250],
];
export default function RollingCounterScreen() {
const custom = useCustomize(CUSTOMIZE);
const counter = useSharedValue<number>(1234);
useAutoplay(async ({ wait }) => {
if (counter.value !== 1234) {
counter.value = 1234;
await wait(1100);
}
await wait(300);
for (const [next, hold] of AUTOPLAY_STEPS) {
counter.value = next(counter.value);
await wait(hold);
}
await wait(1500);
});
return (
<Showcase>
<View
style={[
styles.stage,
{
justifyContent: "center",
alignItems: "center",
flex: 1,
},
]}
>
<RollingCounter
value={counter}
height={custom.height}
width={custom.width}
stagger={custom.stagger}
timingConfig={{
duration: custom.duration,
easing: Easing.bezier(0.2, 1, 0.48, 1),
}}
fontSize={custom.fontSize}
fadeEdges={custom.fadeEdges}
motionBlur={custom.motionBlur}
color={custom.color}
/>
<View style={styles.row}>
<Pressable
style={styles.button}
onPress={() => (counter.value = counter.value - 1)}
>
<Text style={styles.buttonText}>-1</Text>
</Pressable>
<Pressable
style={styles.button}
onPress={() => (counter.value = counter.value + 1)}
>
<Text style={styles.buttonText}>+1</Text>
</Pressable>
<Pressable
style={styles.button}
onPress={() => (counter.value = counter.value + 111)}
>
<Text style={styles.buttonText}>+111</Text>
</Pressable>
<Pressable
style={styles.button}
onPress={() => (counter.value = Math.floor(Math.random() * 5000))}
>
<Text style={styles.buttonText}>random</Text>
</Pressable>
</View>
</View>
</Showcase>
);
}
const styles = StyleSheet.create({
stage: { alignItems: "center", gap: 32 },
row: { flexDirection: "row", gap: 12 },
button: {
paddingHorizontal: 16,
paddingVertical: 10,
borderRadius: 12,
backgroundColor: "#1c1c1e",
},
buttonText: { color: "#fff", fontSize: 14, fontWeight: "600" },
});valueТип number | SharedValue<number>
height?Тип number
width?Тип number
digitStyle?Тип StyleProp<TextStyle>
style?Тип StyleProp<ViewStyle>
springConfig?Spring driver. Omit to use the smoother `timingConfig` roll (default).
Тип Partial<WithSpringConfig>
timingConfig?Timing driver used when `springConfig` is not supplied.
Тип WithTimingConfig
stagger?Delay in ms added per place, cascading right to left. `0` disables it.
Тип number
fadeEdges?Soften the top and bottom of every digit window with a gradient mask.
Тип boolean
motionBlur?Blur and squash each digit in proportion to how fast it is travelling.
Тип boolean
fontSize?Тип number
color?Тип string