Компоненты/Сменный текст

Сменный текст

31 января 2025

Текст перебирает варианты с плавными переходами

Установка

npx astra-rn add dynamic-text
pnpm dlx astra-rn add dynamic-text
yarn dlx astra-rn add dynamic-text
bunx --bun astra-rn add dynamic-text

Файлы

index.tsx
НазадТекст в пыльДалееТекст с фейдом

Вручную

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

npm install expo-blur react-native-reanimated
pnpm add expo-blur react-native-reanimated
yarn add expo-blur react-native-reanimated
bun add expo-blur react-native-reanimated

Скопируйте эти файлы в src/shared/components/molecules/dynamic-text/:

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

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

import { DynamicText } from "@/shared/components/molecules/dynamic-text";
import { DynamicTextItem } from "@/shared/components/molecules/dynamic-text/types";
import * as React from "react";
import { StyleSheet, View } from "react-native";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { Showcase, useCustomize } from "~/showcase";

const greetings: readonly DynamicTextItem[] = [
  { text: "Hello", id: "en" },
  { text: "こんにちは", id: "ja" },
  { text: "Bonjour", id: "fr" },
  { text: "Hola", id: "es" },
  { text: "안녕하세요", id: "ko" },
] as const;

const CUSTOMIZE = [
  { key: "word1", label: "Слово 1", type: "text", default: "Hello", maxLength: 24 },
  { key: "word2", label: "Слово 2", type: "text", default: "こんにちは", maxLength: 24 },
  { key: "word3", label: "Слово 3", type: "text", default: "Bonjour", maxLength: 24 },
  { key: "word4", label: "Слово 4", type: "text", default: "Hola", maxLength: 24 },
  { key: "word5", label: "Слово 5", type: "text", default: "안녕하세요", maxLength: 24 },
  { key: "interval", label: "Интервал", type: "slider", min: 400, max: 5000, step: 100, unit: "ms", default: 1600 },
  { key: "animationDuration", label: "Длительность", type: "slider", min: 80, max: 1200, step: 20, unit: "ms", default: 320 },
  { key: "preset", label: "Анимация", type: "select", options: [{ value: "fade", label: "Появление" }, { value: "zoom", label: "Масштаб" }], default: "fade" },
  { key: "direction", label: "Направление", type: "select", options: [{ value: "up", label: "Вверх" }, { value: "down", label: "Вниз" }], default: "up" },
  { key: "fontSize", label: "Размер шрифта", type: "slider", min: 12, max: 56, step: 1, unit: "px", default: 24 },
  { key: "textColor", label: "Цвет текста", type: "color", default: "#ffffff" },
  { key: "dotSize", label: "Размер точки", type: "slider", min: 0, max: 16, step: 1, unit: "px", default: 5 },
  { key: "dotColor", label: "Цвет точки", type: "color", default: "#ffffff" },
  { key: "background", label: "Фон", type: "color", default: "#0a0a0a" },
  { key: "loop", label: "Повтор", type: "toggle", default: true },
] as const;

export default function App(): React.JSX.Element & React.ReactNode {
  const custom = useCustomize(CUSTOMIZE);
  const words = [custom.word1, custom.word2, custom.word3, custom.word4, custom.word5];
  const items = React.useMemo<DynamicTextItem[]>(
    () => greetings.map((item, index) => ({ ...item, text: words[index] })),
    [custom.word1, custom.word2, custom.word3, custom.word4, custom.word5],
  );
  const timing = React.useMemo(
    () => ({ interval: custom.interval, animationDuration: custom.animationDuration }),
    [custom.interval, custom.animationDuration],
  );
  return (
    <Showcase>
      <GestureHandlerRootView style={{ flex: 1 }}>
        <View style={[styles.container, { backgroundColor: custom.background }]}>
          <DynamicText
            items={items}
            initialIndex={2}
            timing={timing}
            paused={false}
            loop={custom.loop}
            animationPreset={custom.preset as "fade" | "zoom"}
            animationDirection={custom.direction as "up" | "down"}
            text={{ fontSize: custom.fontSize, color: custom.textColor }}
            dot={{
              size: custom.dotSize,
              color: custom.dotColor,
            }}
          />
        </View>
      </GestureHandlerRootView>
    </Showcase>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#0a0a0a",
    alignItems: "center",
    justifyContent: "center",
  },
});

Пропсы

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

Тип readonly DynamicTextItem[] | readonly string[]

loop?

Тип boolean

loopCount?

Тип number

animationPreset?

Тип AnimationPreset

animationDirection?

Тип AnimationDirection

customEntering?

Тип EnteringAnimation

customExiting?

Тип ExitingAnimation

timing?

Тип Partial<TimingConfig>

text?

Тип Partial<TextConfig>

dot?

Тип Partial<DotConfig>

containerStyle?

Тип StyleProp<ViewStyle>

contentStyle?

Тип StyleProp<ViewStyle>

onAnimationComplete?

Тип () => void

onIndexChange?

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

paused?

Тип boolean

initialIndex?

Тип number

accessibilityLabel?

Тип string

DynamicTextItem

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

Тип string

id?

Тип string