Карточка с двумя сторонами-картинками переворачивается в ту сторону, с которой её коснулись: тап по левой половине переворачивает влево, по правой — вправо. В вебе направление задаёт сторона, с которой зашёл курсор, а пока он над карточкой, она немного наклоняется вслед за ним, по поверхности скользит блик и тень становится глубже.
С клавиатуры в вебе карточка переворачивается пробелом или Enter. Переворот идёт на пружине в UI-потоке Reanimated; при «Уменьшении движения» наклон отключается, а переворот происходит мгновенно. Работает на iOS, Android и в вебе.
Поставьте зависимости:
npm install react-native-gesture-handler react-native-reanimated react-native-svgpnpm add react-native-gesture-handler react-native-reanimated react-native-svgyarn add react-native-gesture-handler react-native-reanimated react-native-svgbun add react-native-gesture-handler react-native-reanimated react-native-svgСкопируйте эти файлы в src/shared/components/molecules/direction-aware-flip-card/:
Проверьте алиас путей. Импорты в коде выше записаны так, как их пишет astra-rn add: @/shared/components, @/shared/utils и @/shared/hooks. Нужен алиас "@/*": ["./src/*"] в tsconfig.json — или поправьте импорты под свои пути.
import React from "react";
import { ScrollView, StyleSheet, View } from "react-native";
import { DirectionAwareFlipCard } from "@/shared/components/molecules/direction-aware-flip-card";
import { PHOTO_SOURCES } from "~/assets/photos";
import { Showcase, useCustomize } from "~/showcase";
const CUSTOMIZE = [
{ key: "width", label: "Ширина", type: "slider", min: 200, max: 480, step: 10, unit: "px", default: 360 },
{ key: "height", label: "Высота", type: "slider", min: 300, max: 760, step: 10, unit: "px", default: 620 },
{ key: "radius", label: "Скругление", type: "slider", min: 0, max: 48, step: 1, unit: "px", default: 12 },
{ key: "duration", label: "Длительность переворота", type: "slider", min: 0.15, max: 1.5, step: 0.05, unit: "с", default: 0.45 },
{ key: "frontSrc", label: "Лицевая сторона", type: "image", default: PHOTO_SOURCES["cinematic-carousel-2"] },
{ key: "backSrc", label: "Обратная сторона", type: "image", default: PHOTO_SOURCES["cinematic-carousel-4"] },
] as const;
export default function DirectionAwareFlipCardScreen() {
const custom = useCustomize(CUSTOMIZE);
return (
<Showcase>
<ScrollView contentContainerStyle={styles.stage}>
<View style={styles.frame}>
<DirectionAwareFlipCard
frontSrc={custom.frontSrc}
backSrc={custom.backSrc}
width={custom.width}
height={custom.height}
radius={custom.radius}
duration={custom.duration}
/>
</View>
</ScrollView>
</Showcase>
);
}
const styles = StyleSheet.create({
stage: {
flexGrow: 1,
alignItems: "center",
justifyContent: "center",
paddingVertical: 48,
},
frame: {
width: "100%",
alignItems: "center",
justifyContent: "center",
},
});frontSrcТип FlipCardImage
backSrcТип FlipCardImage
frontAlt?Тип string
backAlt?Тип string
width?Тип number
height?Тип number
radius?Тип number
duration?Тип number
style?Тип StyleProp<ViewStyle>