본문 바로가기
React

React native 로 스와이프 애니메이션

by 윤-찬미 2022. 4. 11.

install

yarn add react-native-swipe-gestures

use

  • react-native-swipe-gestures
  • react-native animation event

swipe 시에 텍스트 변경하게 하기

react-native-swipe-gestures 라이브러리를 이용하면, 손쉽게 스와이프 액션을 캐치할 수 있습니다.

import React, { useState } from 'react'
import { SafeAreaView, StyleSheet, Text } from 'react-native';
import GestureRecognizer from 'react-native-swipe-gestures';

function Intro() {
  // swipe 시에 바꿔줄 텍스트 모음 입니다.
  const stepContent = ["text1", "text2"];

  // swipe할때마다 step 을 하나씩 올려주거나 내려줄 것 입니다.
  const [stepState, setStepState] = useState(0);

  const handleNext = () => {
	// stepContent 의 길이 - 1 일때는 더이상 다음 스와이프에서 보여줄 콘텐츠가 없으므로 return 해줍니다.
    if (stepState === stepContent.length - 1) return;
    setStepState((prev) => ++prev);
  }
  const handleBack = () => {
    // stepContent 의 길이 0 일때는 더이상 이전 스와이프에서 보여줄 콘텐츠가 없으므로 return 해줍니다.
    if (stepState === 0) return;
    setStepState((prev) => --prev);
  }

  return (
    <SafeAreaView>
      <GestureRecognizer
        onSwipeLeft={handleNext}
        onSwipeRight={handleBack}
      >
        <Text>{stepContent[stepState]}</Text>
      </GestureRecognizer>
    </SafeAreaView>
  )
}

export default Intro;

 

swipe 시에 애니메이션 주기

react native 에는 Animated 라는 것을 사용할 수 있습니다.

const myItem = useRef(new Animated.Value(0)).current;

Animated.timing(
  myItem,
  {
    toValue: 1,
    duration: 1000,
    useNativeDriver: true
  }
).start();

 

위 코드에서 value 값을 활용해 opacity 값을 조정해 보겠습니다.

아래는 렌더링할 아이템 입니다. 렌더링할 텍스트와 ref 값을 담았습니다.

const stepContent = [
	{
	  contentText: 'item1',
	  ref: useRef(new Animated.Value(1)).current
	}, 
	{
	  contentText: 'item2',
	  ref: useRef(new Animated.Value(0)).current
	},
	{
	  contentText: 'item3',
	  ref: useRef(new Animated.Value(0)).current
	}
];

 

화면에 보이는 텍스트만 투명도 1을 주고 나머지는 0으로 다시 만들어주는 처리를 했습니다.

 useEffect(() => {
    for (let i = 0; i < stepContent.length; i++) {
      if (i === stepState) {
        Animated.timing(
          stepContent[stepState].ref,
          {
            toValue: 1,
            duration: 1000,
            useNativeDriver: true
          }
        ).start();
	      return;
      } 
      Animated.timing(
        stepContent[i].ref,
        {
          toValue: 0,
          duration: 0,
          useNativeDriver: true
        }
      ).start();
    }
}, [stepContent[stepState].ref]);

 

이제 opacity값을 조정하겠습니다.

<Animated.View style={{ opacity: stepContent[stepState].ref }}>
  <Text>{stepContent[stepState].contentText}</Text>
</Animated.View>

 

전체 코드

import React, { RefObject, useEffect, useRef, useState } from 'react'
import { StyleSheet, View, Text, Animated } from 'react-native';
import GestureRecognizer from 'react-native-swipe-gestures';
import IntroStone from './../assets/images/introStone.svg';

function IntroWrapper() {
  const stepContent = [
    {
      contentText: 'item1',
      ref: useRef(new Animated.Value(1)).current
    }, 
    {
      contentText: 'item2',
      ref: useRef(new Animated.Value(0)).current
    },
    {
      contentText: 'item3',
      ref: useRef(new Animated.Value(0)).current
    }
  ];

  const [stepState, setStepState] = useState(0);

  useEffect(() => {
    for (let i = 0; i < stepContent.length; i++) {
      if (i === stepState) {
        Animated.timing(
          stepContent[stepState].ref,
          {
            toValue: 1,
            duration: 1000,
            useNativeDriver: true
          }
        ).start();
	      return;
      } 
      Animated.timing(
        stepContent[i].ref,
        {
          toValue: 0,
          duration: 0,
          useNativeDriver: true
        }
      ).start();
    }
  }, [stepContent[stepState].ref]);

  const handleNext = () => {
    if (stepState === stepContent.length - 1) return;
    setStepState((prev) => ++prev);
  }
  const handleBack = () => {
    if (stepState === 0) return;
    setStepState((prev) => --prev);
  }
  return (
    <GestureRecognizer
      onSwipeLeft={handleNext}
      onSwipeRight={handleBack}
    >
      <Animated.View style={{ opacity: stepContent[stepState].ref }}>
        <Text>{stepContent[stepState].contentText}</Text>
      </Animated.View>
    </GestureRecognizer>
  )
}

export default IntroWrapper;