React Native - Animation

2026. 2. 11. 15:28ยท๐Ÿ›ธ React Native

React Native

 

 

โœ… ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋ณด๋Š” Animation


import { useEffect, useState } from "react";
import styled from "styled-components/native";

const Container = styled.View`
  flex: 1;
  justify-content: center;
  align-items: center;
`;

const Box = styled.TouchableOpacity`
  background-color: tomato;
  width: 200px;
  height: 200px;
`;

export default function App() {
  const [y, setY] = useState(0);
  const [intervalId, setIntervalId] = useState(null);
  const moveUp = () => {
    const id = setInterval(() => setY((prev) => prev + 1), 10);
    setIntervalId(id);
  };
  useEffect(() => {
    if (y === 200) {
      clearInterval(intervalId);
    }
  }, [y, intervalId]);
  console.log("rendering");
  return (
    <Container>
      <Box onPress={moveUp} style={{ transform: [{ translateY: y }] }} />
    </Container>
  );
}

 

๊ธด ์ฝ”๋“œ์™€ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์ด๋ฃจ์–ด์งˆ ๋•Œ๋งˆ๋‹ค ๋ Œ๋”๋ง์„ ํ•˜๋Š” ํผํฌ๋จผ์Šค ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด React Native์˜ Animated๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

 

โœ… Animated


https://reactnative.dev/docs/animated

 

Animated · React Native

The Animated library is designed to make animations fluid, powerful, and painless to build and maintain. Animated focuses on declarative relationships between inputs and outputs, configurable transforms in between, and start/stop methods to control time-ba

reactnative.dev

 

1. animation์„ ์œ„ํ•œ value๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด state๋‚˜ ๋‹ค๋ฅธ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  new Animated.Value()๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

const Y = new Animated.Value(0);

 

2. ์ ˆ๋Œ€ value๋ฅผ ์ง์ ‘ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š”๋‹ค. (๋ฐ‘ 3๊ฐ€์ง€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ€๊ฒฝํ•œ๋‹ค.)

Animated.decay() starts with an initial velocity and gradually slows to a stop.
Animated.spring() provides a basic spring physics model.
Animated.timing() animates a value over time using easing functions.

 

3. ์˜ค์ง Animatable Components์—๋งŒ animation์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค. (์•„๋ฌด๊ฑฐ์—๋‚˜ ์ฆ‰์‹œ animation์„ ์ค„ ์ˆ˜ ์—†๋‹ค.)

ex)

Animated.Image
Animated.ScrollView
Animated.Text
Animated.View
Animated.FlatList
Animated.SectionList

 

animation์„ ์ฃผ๊ณ  ์‹ถ์€ components๊ฐ€ ์œ„์— ํ•ด๋‹นํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด createAnimatedComponent()๋ฅผ ์‚ฌ์šฉํ•ด์„œ animated components๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

 

<option 1>

const Box = styled(Animated.createAnimatedComponent(TouchableOpacity))`
  background-color: tomato;
  width: 200px;
  height: 200px;
`;

๋‹จ์ : TouchableOpacity๋ฅผ import ํ•ด์•ผ ํ•œ๋‹ค.

 

<option 2>

const Box = styled.TouchableOpacity`
  background-color: tomato;
  width: 200px;
  height: 200px;
`;

const AnimatedBox = Animated.createAnimatedComponent(Box);

 

Usage

export default function App() {
  const [up, setUp] = useState(false);
  const Y_POSITION = useRef(new Animated.Value(300)).current;
  const toggleUp = () => setUp((prev) => !prev);
  const moveUp = () => {
    Animated.timing(Y_POSITION, {
      toValue: up ? 300 : -300,
      useNativeDriver: true,
      easing: Easing.cubic,
    }).start(toggleUp);
  };
  const opacity = Y_POSITION.interpolate({
    inputRange: [-300, 0, 300],
    outputRange: [1, 0, 1],
  });
  Y_POSITION.addListener(() => console.log(opacity));
  return (
    <Container>
      <AnimatedBox
        onPress={moveUp}
        style={{ opacity, transform: [{ translateY: Y_POSITION }] }}
      />
    </Container>
  );
}

 

extrapolate

interpolate์˜ inputRange๊ฐ€ ๋ฒ”์œ„๋ฅผ ์ดˆ๊ณผํ–ˆ์„ ๋•Œ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ง€ ๋ช…์‹œํ•  ์ˆ˜ ์žˆ๋Š” ์†์„ฑ

  const rotation = position.interpolate({
    inputRange: [-windowWidth / 3, windowWidth / 3],
    outputRange: ["-15deg", "15deg"],
    extrapolate: "extend",
  });

extend(default): ๋ฒ”์œ„๊ฐ€ ๋„˜์–ด๊ฐ€๋„ ๊ฐ™์€ ๋น„์œจ๋กœ ๊ณ„์† ๊ณ„์‚ฐ

clamp: ๋ฒ”์œ„๊ฐ€ ๋„˜์–ด๊ฐ€๋ฉด ๋๊ฐ’์œผ๋กœ ๊ณ ์ •

identity: input๊ฐ’์„ ๊ทธ๋Œ€๋กœ output์œผ๋กœ ๋ฐ˜ํ™˜

 

getTranslateTransform()

translateY: position.y ํ˜น์€ translateX: position.x ์ด๋ ‡๊ฒŒ ์“ธ ํ•„์š” ์—†์ด getTranslateTransform()์œผ๋กœ ๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

(translate ๊ฐ’์„ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜)

    <Container>
      <AnimatedBox
        onPress={moveUp}
        style={{
          transform: [
            ...position.getTranslateTransform(),
            { rotate: rotation },
          ],
          borderRadius,
          backgroundColor,
        }}
      />
    </Container>

 

 

โœ… PanResponder


https://reactnative.dev/docs/panresponder

 

PanResponder · React Native

PanResponder reconciles several touches into a single gesture. It makes single-touch gestures resilient to extra touches, and can be used to recognize basic multi-touch gestures.

reactnative.dev

 

 

onStartShouldSetPanResponder

์ด ์†์„ฑ์€ ํ•จ์ˆ˜๋ฅผ ๋ฐ›์œผ๋ฉฐ, ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ true ์—ฌ๋ถ€์— ๋”ฐ๋ผ View๊ฐ€ touch๋ฅผ ๊ฐ์ง€ํ•  ์ง€ ๊ฒฐ์ •ํ•ด์ค€๋‹ค.

  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponder: () => true,
    }),
  ).current;

 

onPanResponderMove

์›€์ง์ž„์ด ๊ฐ์ง€๋˜์—ˆ์„ ๋•Œ ๋™์ž‘์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์†์„ฑ

(์ฝœ๋ฐฑ ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ evt, gestureState๋ฅผ ๋ฐ›๋Š”๋‹ค)

  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onPanResponderMove: (_, { dx, dy }) => {
        position.setValue({
          x: dx,
          y: dy,
        });
      },
    }),
  ).current;

 

onPanResponderRelease

์›€์ง์ž„์ด ๋๋‚ฌ์„ ๋•Œ ๋™์ž‘์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์†์„ฑ

const panResponder = useRef(
PanResponder.create({
  onStartShouldSetPanResponder: () => true,
  onPanResponderMove: (_, { dx, dy }) => {
    position.setValue({
      x: dx,
      y: dy,
    });
  },
  onPanResponderRelease: () => {
    Animated.spring(position, {
      toValue: {
        x: 0,
        y: 0,
      },
      useNativeDriver: true,
    }).start();
  },
}),
).current;

 

onPanResponderGrant

์‚ฌ์šฉ์ž๊ฐ€ ํ„ฐ์น˜๋ฅผ ์‹œ์ž‘ํ•  ๋•Œ ๋”ฑ ํ•œ ๋ฒˆ ํ˜ธ์ถœ๋œ๋‹ค.

๋“œ๋ž˜๊ทธ๋ฅผ ๋๋‚ด๊ณ  ๋‹ค์‹œ ๋“œ๋ž˜๊ทธ๋ฅผ ์‹œ์ž‘ํ•  ๋•Œ๋งˆ๋‹ค 0, 0 ์œ„์น˜๋กœ ๋Œ์•„๊ฐ„๋‹ค(setValue์— dx์™€ dy๋ฅผ ์ฃผ๊ณ  ์žˆ๋Š”๋ฐ dx์™€ dy๋Š” ์ด๋™ํ•œ ๊ฑฐ๋ฆฌ์ด๊ธฐ ๋•Œ๋ฌธ์— 0์œผ๋กœ ์ดˆ๊ธฐํ™” ๋˜๊ธฐ ๋•Œ๋ฌธ)

extractOffset()์œผ๋กœ ํ•ด๊ฒฐํ•œ๋‹ค.

  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onPanResponderGrant: () => {
        position.extractOffset();
      },
      onPanResponderMove: (_, { dx, dy }) => {
        console.log("moving");
        position.setValue({
          x: dx,
          y: dy,
        });
      },
      onPanResponderRelease: () => {
        console.log("touch finished");
      },
    }),
  ).current;

 

 

โœ… Spring์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ๋น ๋ฅด๊ฒŒ ๋๋‚ด๋Š” ๋ฐฉ๋ฒ•


spring animation์€ ๋๋‚˜๊ธฐ๊นŒ์ง€ ์•ฝ๊ฐ„์˜ ํ…€์ด ์žˆ๋‹ค.

restSpeedThreshold

- ์†๋„ ์ž„๊ณ„๊ฐ’

- ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋๋‚œ๊ฑธ๋กœ ๊ฐ„์ฃผํ•˜๋Š” ์†๋„(์ดˆ๋‹น ๋ช‡ ํ”ฝ์…€๋งŒํผ ์›€์ง์ด๊ณ  ์žˆ๋‚˜์— ๋Œ€ํ•œ ๊ฐ’)

- ๊ธฐ๋ณธ๊ฐ’์€ 0.001

restDisplacementThreshold

- ๊ฑฐ๋ฆฌ ์ž„๊ณ„๊ฐ’

- ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๋๋‚œ ๊ฑธ๋กœ ๊ฐ„์ฃผํ•˜๋Š” ๊ฑฐ๋ฆฌ

- ๊ธฐ๋ณธ๊ฐ’์€ 0.001

 

 

โœ… LayoutAnimation


https://reactnative.dev/docs/layoutanimation

 

LayoutAnimation · React Native

Automatically animates views to their new positions when the next layout happens.

reactnative.dev

 

'๐Ÿ›ธ React Native' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

React Native - ์œ ์šฉํ•œ Component, API  (0) 2026.01.30
React Native - react native web swiper  (0) 2026.01.27
React Native - Dark Mode  (0) 2026.01.26
React Native - npx expo prebuild, ๊ธฐ๊ธฐ ๋ฌด์„  ์—ฐ๊ฒฐ ๋ชจ๋‹ˆํ„ฐ๋ง  (0) 2026.01.21
React Native - React Navigation  (0) 2026.01.21
'๐Ÿ›ธ React Native' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • React Native - ์œ ์šฉํ•œ Component, API
  • React Native - react native web swiper
  • React Native - Dark Mode
  • React Native - npx expo prebuild, ๊ธฐ๊ธฐ ๋ฌด์„  ์—ฐ๊ฒฐ ๋ชจ๋‹ˆํ„ฐ๋ง
j2yonghwa
j2yonghwa
Trying to be a fullstack developer ๐Ÿš€
  • j2yonghwa
    j2yonghwa
    j2yonghwa
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (156)
      • โฐ Daily WakaTime (1)
      • ๐Ÿ–๏ธ ๋…ธ๋งˆ๋“œ์ฝ”๋” (2)
      • ๐Ÿบ Dev Setup (3)
      • ๐Ÿ”ญ Tech Info (1)
      • ๐Ÿšซ Error (1)
      • ๐Ÿ“‚ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (23)
      • ♣๏ธ Next.js 14 (10)
      • ♠๏ธ Next.js 12 (20)
      • ๐Ÿ›ธ React Native (12)
      • ๐Ÿฆ‹ TypeScript (1)
      • ๐Ÿ Python (2)
      • ๐ŸŒŠ TailwindCSS (4)
      • ๐Ÿงฉ SQL (25)
      • ๐Ÿ’Ž Prisma (5)
      • ๐ŸŒฑ MongoDB (4)
      • ๐ŸŽฏ Redis (1)
      • ๐Ÿงฌ GraphQL (2)
      • ๐Ÿ”ฅ Firebase (7)
      • ๐Ÿ’ธ Third-Party Services (2)
      • ๐Ÿ•ธ๏ธ Web (1)
      • ๐Ÿ† ์ฝ”๋”ฉํ…Œ์ŠคํŠธ (23)
      • ๐Ÿ“™ ๋ชจ๋”ฅ๋‹ค (5)
      • ๐Ÿ“— ์ฝ”ํ…Œ ํ•ฉ๊ฒฉ์ž ๋˜๊ธฐ -JS- (0)
      • ๐Ÿ“˜ ํด๋ฆฐ์ฝ”๋“œ (0)
      • ๐Ÿฏ ๊ฟ€ํŒ ๐Ÿ (1)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
  • ๋งํฌ

    • ๊นƒํ—™
  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    mongoDB
    0๋ ˆ๋ฒจ
    tailwindcss
    Python
    ๋ชจ๋”ฅ๋‹ค
    React Native
    SQL
    ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ
    Next.js
    ์ฝ”๋”ฉํ…Œ์ŠคํŠธ ์ž…๋ฌธ
    next.js 14
    PostgreSQL
    Prisma
    MySQL
    ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
    next.js 12
    dev setup
    Firebase
    API
    react router
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.3
j2yonghwa
React Native - Animation
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”