Поставьте зависимости:
npm install @shopify/react-native-skia expo-haptics react-native-gesture-handler react-native-reanimated react-native-workletspnpm add @shopify/react-native-skia expo-haptics react-native-gesture-handler react-native-reanimated react-native-workletsyarn add @shopify/react-native-skia expo-haptics react-native-gesture-handler react-native-reanimated react-native-workletsbun add @shopify/react-native-skia expo-haptics react-native-gesture-handler react-native-reanimated react-native-workletsСкопируйте эти файлы в src/shared/components/base/ruler/:
Проверьте алиас путей. Импорты в коде выше записаны так, как их пишет astra-rn add: @/shared/components, @/shared/utils и @/shared/hooks. Нужен алиас "@/*": ["./src/*"] в tsconfig.json — или поправьте импорты под свои пути.
import React, { useRef, useState } from "react";
import { StyleSheet, Text, View, useWindowDimensions } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import Ruler from "@/shared/components/base/ruler";
import type { IRulerHandle } from "@/shared/components/base/ruler/types";
import { Showcase, hexToRgb, useAutoplay, useCustomize } from "~/showcase";
const CUSTOMIZE = [
{ key: "label", label: "Подпись", type: "text", default: "Weight", maxLength: 20 },
{ key: "unit", label: "Единица", type: "text", default: "kg", maxLength: 8 },
{ key: "valueColor", label: "Цвет значения", type: "color", default: "#ffffff" },
{ key: "activeTickColor", label: "Активное деление", type: "color", default: "#b56c1d" },
{ key: "tickColor", label: "Цвет делений", type: "color", default: "#ffffff" },
{ key: "tickOpacity", label: "Прозрачн. делений", type: "slider", min: 0, max: 1, step: 0.05, default: 0.3 },
{ key: "step", label: "Шаг делений", type: "slider", min: 8, max: 40, step: 1, unit: "px", default: 18 },
{ key: "notchHeight", label: "Высота деления", type: "slider", min: 10, max: 100, step: 1, unit: "px", default: 40 },
{ key: "notchWidth", label: "Толщина деления", type: "slider", min: 1, max: 8, step: 0.5, unit: "px", default: 3 },
] as const;
function rgba(hex: string, alpha: number) {
const { r, g, b } = hexToRgb(hex);
return `rgba(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)},${alpha})`;
}
export default function RulerScreen() {
const custom = useCustomize(CUSTOMIZE);
const { width: screenWidth } = useWindowDimensions();
const rulerWidth = Math.min(400, Math.floor(screenWidth));
const [value, setValue] = useState<number>(0);
const rulerRef = useRef<IRulerHandle>(null);
useAutoplay(async ({ wait }) => {
rulerRef.current?.scrollTo(5, 1100);
await wait(1500);
rulerRef.current?.scrollTo(30, 2100);
await wait(2600);
rulerRef.current?.scrollTo(43, 950);
await wait(2200);
});
return (
<Showcase>
<SafeAreaView style={styles.container}>
<View style={styles.content}>
<Text style={styles.label}>{custom.label}</Text>
<View style={styles.valueRow}>
<Text style={[styles.value, { color: custom.valueColor }]}>{value}</Text>
<Text style={styles.unit}>{custom.unit}</Text>
</View>
</View>
<View style={styles.rulerRow}>
<Ruler
key={`${custom.step}-${rulerWidth}`}
ref={rulerRef}
height={150}
width={rulerWidth}
minValue={5}
maxValue={50}
step={custom.step}
tickColor={rgba(custom.tickColor, custom.tickOpacity)}
activeTickColor={custom.activeTickColor}
notchHeight={custom.notchHeight}
notchWidth={custom.notchWidth}
onValueChange={setValue}
/>
</View>
</SafeAreaView>
</Showcase>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: "center", backgroundColor: "#0a0a0a" },
content: { alignItems: "center", gap: 9 },
rulerRow: { alignItems: "center" },
label: {
fontSize: 15,
color: "rgba(255,255,255,0.5)",
letterSpacing: 1,
textTransform: "uppercase",
},
valueRow: { flexDirection: "row", alignItems: "baseline", gap: 6 },
value: { fontSize: 72, color: "#fff", fontWeight: "600" },
unit: { fontSize: 24, color: "rgba(255,255,255,0.5)" },
});Необязательный ref с типом IRulerHandle даёт метод scrollTo(value, duration?): линейка плавно доезжает до значения value (в пределах minValue–maxValue) за duration мс, по умолчанию 900. Без ref линейка работает только от жестов, как и раньше.
heightТип number
widthТип number
minValueТип number
maxValueТип number
stepТип number
onScroll?Тип (value: number) => void
onValueChange?Тип (value: number) => void
tickColor?Тип string
activeTickColor?Тип string
backgroundColor?Тип string
notchHeight?Тип number
notchWidth?Тип number
enableHaptics?Тип boolean
animateOnMount?Тип boolean
ref?Тип Ref<IRulerHandle>
indexТип number
tickXТип number
xCenterТип number
yCenterТип number
translateXТип SharedValue<number>
mountAnimationТип SharedValue<number>
notchHeightТип number
notchWidthТип number
tickColorТип string
activeTickColorТип string
stepТип number