Компоненты/Бесконечное меню

Бесконечное меню

Pro
24 мая 2024

Глобальное бесконечное радиальное меню на Reanimated, Skia и Gesture Handler

Установка

import { useEffect, useMemo } from "react";
import Animated, { useSharedValue } from "react-native-reanimated";
import { StyleSheet, View } from "react-native";

Установка через CLIPro

Команда станет доступна после оформления Pro.

Оформить ProВойти

Файлы

index.tsx
НазадКолесо изображенийДалееБесконечный холст

Вручную

Поставьте зависимости:

npm install @shopify/react-native-skia react-native-gesture-handler react-native-reanimated react-native-worklets
pnpm add @shopify/react-native-skia react-native-gesture-handler react-native-reanimated react-native-worklets
yarn add @shopify/react-native-skia react-native-gesture-handler react-native-reanimated react-native-worklets
bun add @shopify/react-native-skia react-native-gesture-handler react-native-reanimated react-native-worklets

Скопируйте эти файлы в src/shared/components/organisms/infinite-menu/:

index.tsx
import { useEffect, useMemo } from "react";
import Animated, { useSharedValue } from "react-native-reanimated";
import { StyleSheet, View } from "react-native";
// Полный исходник открывается с подпиской Pro
export interface InfiniteMenuProps {
speed?: number;
intensity?: number;
palette?: "aurora" | "mono";
interactive?: boolean;
}
export function InfiniteMenu({
speed = 1,
intensity = 0.6,
interactive = true,
}: InfiniteMenuProps) {
const progress = useSharedValue(0);
const frame = useMemo(() => createFrame(speed), [speed]);
useEffect(() => {
// …

Код доступен по подпискеPro

Исходник «Бесконечное меню» открывается с подпиской Pro. Уже оформили? Войдите в аккаунт.

Оформить ProВойти

Проверьте алиас путей. Импорты в коде выше записаны так, как их пишет astra-rn add: @/shared/components, @/shared/utils и @/shared/hooks. Нужен алиас "@/*": ["./src/*"] в tsconfig.json — или поправьте импорты под свои пути.

Использование

usage.tsx
import { useEffect, useMemo } from "react";
import Animated, { useSharedValue } from "react-native-reanimated";
import { StyleSheet, View } from "react-native";
// Полный исходник открывается с подпиской Pro
export interface InfiniteMenuProps {
speed?: number;
intensity?: number;
palette?: "aurora" | "mono";
interactive?: boolean;
}
export function InfiniteMenu({
speed = 1,
intensity = 0.6,
interactive = true,
}: InfiniteMenuProps) {
const progress = useSharedValue(0);
const frame = useMemo(() => createFrame(speed), [speed]);
useEffect(() => {
// …

Код доступен по подпискеPro

Исходник «Бесконечное меню» открывается с подпиской Pro. Уже оформили? Войдите в аккаунт.

Оформить ProВойти

Отдаление из кода

Необязательный проп zoomed отодвигает камеру так же, как при зажатом пальце (на величину zoomOnDrag), например вместе с autoRotateSpeed для демонстрации вращения. По умолчанию false — отдаление включается только жестом, как и раньше.

Пропсы

Пропс
Описание
items

Тип IMenuItem[]

projectionScale?

Explicit projection scale in px. Overrides the auto-fit + `scale`.

Тип number

backgroundColor?

Тип string

style?

Тип StyleProp<ViewStyle>

sphereRadius?

Тип number

cameraDistance?

Camera distance from the sphere centre. Smaller = stronger perspective.

Тип number

discSize?

Disc radius as a fraction of the projection scale.

Тип number

depthScaleRange?

`[equator, pole]` size factor, interpolated by |depth|.

Тип readonly [number, number]

placeholderColor?

Fill used for discs whose image has not loaded yet.

Тип string

imageFit?

Тип Fit

discBorderWidth?

Тип number

discBorderColor?

Тип string

minDiscRadius?

Discs smaller than this (in px) are skipped.

Тип number

dragSensitivity?

How much of each finger delta is applied per frame.

Тип number

dragAmplification?

Тип number

inertia?

Glide decay — lower spins longer after release.

Тип number

snapEnabled?

Snap the nearest disc to face the camera when idle.

Тип boolean

snapStrength?

Тип number

zoomOnDrag?

Extra camera pull-back while dragging. `0` disables the zoom-out.

Тип number

zoomed?

Тип boolean

autoRotateSpeed?

Idle spin in radians per second. `0` (default) disables it.

Тип number

onItemPress?

Тип (item: IMenuItem, index: number) => void

renderOverlay?

Rendered above the canvas; fades out while the sphere is moving.

Тип (state: IMenuState) => ReactNode

overlayFadeInDuration?

Overlay fade-out timing, in ms, when the sphere starts moving.

Тип number

overlayFadeOutDuration?

Overlay fade-in timing, in ms, when the sphere settles.

Тип number

overlayRestingScale?

Scale the overlay shrinks to while the sphere is moving.

Тип number

IMenuItem

Пропс
Описание
image

Тип string

title?

Optional payload — handy for `renderOverlay` and the press callbacks.

Тип string

description?

Тип string

data?

Тип unknown