Компоненты/Флажок

Флажок

31 января 2025

Флажок, который плавно дорисовывает галочку при включении

Установка

npx astra-rn add check-box
pnpm dlx astra-rn add check-box
yarn dlx astra-rn add check-box
bunx --bun astra-rn add check-box

Файлы

index.tsx
НазадКарусель-веерДалееЦветное кольцо

Вручную

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

npm install react-native-reanimated react-native-svg
pnpm add react-native-reanimated react-native-svg
yarn add react-native-reanimated react-native-svg
bun add react-native-reanimated react-native-svg

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

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

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

import React, { useCallback, useState } from "react";
import { Pressable, ScrollView, StyleSheet, Text, View } from "react-native";
import Animated, {
  useAnimatedStyle,
  useSharedValue,
  withSpring,
} from "react-native-reanimated";
import { SafeAreaView } from "react-native-safe-area-context";

import { Checkbox } from "@/shared/components/organisms/check-box";
import { Showcase, useAutoplay, useCustomize } from "~/showcase";

const CUSTOMIZE = [
  { key: "checkmarkColor", label: "Цвет галочки", type: "color", default: "#ffffff" },
  { key: "boxColor", label: "Цвет поля", type: "color", default: "#242424" },
  { key: "boxSize", label: "Размер поля", type: "slider", min: 24, max: 96, step: 1, unit: "px", default: 45 },
  { key: "radius", label: "Скругление", type: "slider", min: 0, max: 48, step: 1, unit: "px", default: 8 },
  { key: "size", label: "Размер галочки", type: "slider", min: 16, max: 110, step: 1, unit: "px", default: 50 },
  { key: "stroke", label: "Толщина линии", type: "slider", min: 1, max: 10, step: 0.5, unit: "px", default: 4 },
  { key: "pressScale", label: "Сжатие", type: "slider", min: 0.5, max: 1, step: 0.01, default: 0.9 },
  { key: "background", label: "Фон", type: "color", default: "#0a0a0a" },
] as const;

const AnimatedPressable = Animated.createAnimatedComponent(Pressable);

export default function CheckBoxScreen() {
  const custom = useCustomize(CUSTOMIZE);
  const [checked, setChecked] = useState(false);
  const scale = useSharedValue(1);

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  const onPressIn = useCallback(() => {
    scale.value = withSpring(custom.pressScale, { damping: 15, stiffness: 300, mass: 0.5 });
  }, [scale, custom.pressScale]);

  const onPressOut = useCallback(() => {
    scale.value = withSpring(1, { damping: 12, stiffness: 250, mass: 0.5 });
  }, [scale]);

  const onPress = useCallback(() => setChecked((prev) => !prev), []);

  useAutoplay(async ({ wait }) => {
    await wait(200);
    for (const hold of [650, 450]) {
      onPressIn();
      try {
        await wait(120);
      } finally {
        onPressOut();
      }
      onPress();
      await wait(hold);
    }
  });

  return (
    <Showcase>
      <View style={[styles.stage, { backgroundColor: custom.background }]}>
        <View style={styles.demo}>
          <AnimatedPressable
            accessibilityRole="checkbox"
            accessibilityState={{ checked }}
            hitSlop={12}
            onPress={onPress}
            onPressIn={onPressIn}
            onPressOut={onPressOut}
            style={animatedStyle}
          >
            <View
              style={[
                styles.checkBoxContainer,
                {
                  width: custom.boxSize,
                  height: custom.boxSize,
                  borderRadius: custom.radius,
                  backgroundColor: custom.boxColor,
                },
              ]}
            >
              <Checkbox
                checked={checked}
                showBorder={false}
                checkmarkColor={custom.checkmarkColor}
                size={custom.size}
                stroke={custom.stroke}
              />
            </View>
          </AnimatedPressable>
        </View>
      </View>
    </Showcase>
  );
}

const styles = StyleSheet.create({
  stage: {
    flex: 1,
    backgroundColor: "#0a0a0a",
    justifyContent: "center",
    alignItems: "center",
  },
  checkBoxContainer: {
    width: 45,
    height: 45,
    backgroundColor: "#242424",
    borderRadius: 8,
    justifyContent: "center",
    alignItems: "center",
  },
  demo: { gap: 12, alignItems: "flex-start" },
});

Пропсы

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

Тип string

checked?

Тип boolean

stroke?

Тип number

showBorder?

Тип boolean

size?

Тип number