What did I learn 블로그의 More about React Native Animations 번역 자료입니다. 번역에 문제가 있다면 댓글 달아주시구요. 원문을 보시기를 추천드립니다.

  1. React Native 애니메이션 소개
  2. 리액트 네이티브 애니메이션에 대한 추가 정보

 

이전 아티클에서는 기본 애니메이션 예제를 살펴 보았습니다. 오늘 우리는 React Native 애니메이션에 대해 더 깊이 파고 들어 우리가 무엇을 달성 할 수 있는지 알아볼 것입니다.

 

Animation types

Animated 모듈은 세 가지 애니메이션 유형을 제공합니다.

  • timing - 시간의 경과에 따라 값을 애니메이션
  • spring - 스프링(spring) 물리 모델을 사용하여 애니메이션(animate)
  • decay (쇠퇴) - 초기 속도에서 시작하여 점차 값을 늦추기

 

Timing

이전 아티클의 예제에서 이미 타이밍을 다루었습니다. 여기서 확인할 수 있습니다.

 

Spring

Spring은 실제 스프링의 물리적 움직임을 모방하는데 도움이 됩니다.

스프링의 동작을 제어하기 위해 세 가지 옵션 그룹을 허용합니다. 단일 구성(single configuration)에서 단일 그룹만 사용할 수 있습니다.

옵션은 다음과 같습니다.

  • friction/tension
  • speed/bounciness
  • swiftness/damping/mass

이 예에서는 friction(마찰)/tension(인장) 옵션에 중점을 둘 것입니다. 공식 문서 페이지에서 모든 옵션에 대한 설명을 찾을 수 있습니다.

그렇다면 friction(마찰)과 tension(인장)은 무엇입니까? friction(마찰)은 스프링이 어느정도 빠르게 안정(calms down)되는지를 제어합니다. tension(인장)은 그 스프링의 에너지입니다.

기본값은 friction(마찰)의 경우 7이고 tension(장력)의 경우 40입니다.

이 예에서는 이전 아티클과 동일한 구성 요소 구조를 사용합니다. 그 구조를 빠르게 기억합시다.

파일 상단에서 컴포넌트에 필요한 모든 모듈을 가져옵니다. animations를 사용하기 위해 Animated 모듈을 가져옵니다

import React from 'react';
import { Animated } from 'react-native';

그다음 예제를 작성할 컴포넌트를 정의합니다. animation 상태(state)를 정의하고 오브젝트를 렌더링하며 스타일을 구성합니다.

class SpringVerticalMotionExample extends React.Component {
  state = {
    animation: new Animated.Value(0)
  }

  render() {
    const animationStyles = {
      transform: [
        { translateY: this.state.animation }
      ]
    };

    return (
      <Animated.View style={[objectStyles.object, animationStyles]}>
      </Animated.View>
    );
  }
}

const objectStyles = {
  object: {
    backgroundColor: 'orange',
    width: 100,
    height: 100
  }
}

그다음 componentDidMount() 콜백을 사용하여 animation을 시작합니다. 다음 예제에서는 componentDidMount() 콜백 만 업데이트하여 다른 유형의 애니메이션을 체크합니다.

이제 스프링 애니메이션 예제로 넘어갈 준비가되었습니다.

componentDidMount() {
  Animated.spring(
    this.state.animation,
    {
      toValue: 250,
      duration: 2000,
      friction: 1,
      tension: 20
    }
  ).start();
}

위의 발췌(excerpt) 부분에서 볼 수 있듯이 애니메이션 값(animation value)과 옵션 세트(set of options)를 받아들이는 Animated.spring 함수를 사용하고 있습니다. 여기서 2 초 이내에 애니메이션 값을 0에서 250으로 변경하겠습니다. friction(마찰) 값을 1로, tension(장력)을 20으로 줄였습니다.

그러면 스프링이 더 빨라집니다.

Spring example

예제의 완전한 소스 코드가 있습니다.

 

Decay

Decay(쇠퇴)는 deceleration(감속) 옵션을 사용하여 초기 속도에서 0까지 값을 animate하는 데 사용됩니다.

state = {
  animation: new Animated.Value(-150)
}

componentDidMount() {
  Animated.decay(
    this.state.animation,
    {
      toValue: 200,
      duration: 2000,
      velocity: 0.95,
      deceleration: 0.998 // By default equals to 0.997
    }
  ).start();
}

이전 기사의 모션 예제를 사용한다는 것을 보여줍니다.

여기에서 상자를 화면 아래로 이동합니다. 상자가 중심 아래 200 지점에서 마무리 선(finishing line)에 도달하면 decay효과가 적용됩니다.

상자는 계속 움직이고 있지만 멈출 때까지 속도가 느려집니다.

아래 예를 확인하십시오. 비교해 보자면 위에 decay 효과가 있고 아래쪽에 motion 예제가 있습니다.

Decay example

Vertical motion example

해당 예제의 소스 코드를 확인하십시오.

 

Loop

애니메이션을 반복하고 싶을 때 Animated.loop 함수를 사용할 수 있습니다. 애니메이션 및 optional 설정을 받습니다.

이전 아티클에서 회전 예제를 가져 와서 두 번 반복하겠습니다.

componentDidMount() {
  const rotateAnimation = Animated.timing(
    this.state.animation,
    {
      toValue: 1,
      duration: 2000
    }
  );

  Animated.loop(
    rotateAnimation,
    {
      iterations: 2
    }
  ).start();
}

반복 옵션을 지정하기 위해 eponymous(시조) 옵션을 전달합니다. 기본적으로 반복 횟수는 -1입니다. 애니메이션이 무한 반복됩니다.

Loop example

소스코드

 

Native driver

Animated 모듈은 React Native의 JavaScript 측에서 애니메이션을 수행하고 단일 스레드를 공유합니다. 그래서 애니메이션이 부드럽게 작동하지 않을 수 있습니다.

useNativeDriver:true 옵션을 사용하여 애니메이션을 네이티브 UI로 움직이는 방법이 있습니다.

예를 들어 네이티브 드라이버를 사용하여 스프링 애니메이션을 실행할 수 있습니다.

componentDidMount() {
  Animated.spring(
    this.state.animation,
    {
      toValue: 250,
      duration: 2000,
      friction: 1,
      tention: 20,
      useNativeDriver: true
    }
  ).start();
}

React Native docs에서 Native Driver에 대한 자세한 내용을 읽을 수 있습니다.

 

Easing

다양한 easing(완화) functions를 애니메이션에 적용 할 수 있습니다. 이 기능을 사용하려면 Easing 모듈을 가져옵니다(import).

import { Animated, Easing } from 'react-native';

그다음 easing 옵션을 timing 애니메이션에 전달할 수 있습니다. bounce 효과를 사용하는 예는 다음과 같습니다.

componentDidMount() {
  Animated.timing(
    this.state.animation,
    {
      toValue: 250,
      duration: 3000,
      easing: Easing.bounce
    }
  ).start();
}

Easing bounce example

해당 예제의 소스 코드입니다.

https://facebook.github.io/react-native/docs/easing 설명서 및 easings.net의 easing functions에 대한 미리 정의 된 모든 시각적 예제에서 더 많은 easing functions를 찾을 수 있습니다.

 

Composition functions

때로는 여러 애니메이션이 함께 작동해야 할 수도 있습니다. 컴포지션 함수를 사용하여 다른 동작을 수행 할 수 있습니다.

sequence부터 시작하겠습니다.

Sequence

시퀀스(sequence)는 여러 애니메이션을 하나씩 실행하는 데 사용됩니다. 이를 위해 애니메이션 배열을 Animated.sequence 함수에 전달하고 시작합니다.

state = {
  transformAnimation: new Animated.Value(0),
  fallAnimation: new Animated.Value(0)
}

componentDidMount() {
  const transformToBallAnimation = Animated.timing(
    this.state.transformAnimation,
    {
      toValue: 50,
      duration: 1000
    }
  );

  const fallAnimation = Animated.timing(
    this.state.fallAnimation,
    {
      toValue: 250,
      duration: 3000,
      easing: Easing.bounce
    }
  );

  Animated.sequence([
    transformToBallAnimation,
    fallAnimation
  ]).start();
}

다음은 render 메서드입니다. 하나의 애니메이션 값은 경계 반경을 업데이트하고 다른 하나는 동작을 담당합니다.

render() {
  const animationStyles = {
    borderRadius: this.state.transformAnimation,
    transform: [
      { translateY: this.state.fallAnimation }
    ]
  };

  return (
    <Animated.View style={[objectStyles.object, animationStyles]}>
    </Animated.View>
  );
}

2개의 애니메이션(transformAnimation, fallAnimation)이 있습니다. 첫 번째(transformAnimation)는 상자를 공으로 변형시킵니다. 두번째 (fallAnimation)는 공을 화면 아래로 이동하고 바운스 효과를 적용합니다.

 

Sequence example (이미지 수정, 원문과 이미지 다름 원문에 이미지 오류가 있음)

Easing bounce example

보다시피 변형(transforming) 애니메이션이 진행중일 동안 공이 움직이지 않습니다.

예제의 소스코드입니다.

 

Parallel

동시에 여러 애니메이션을 시작할 수 있습니다. Sequence 대신 Parallel을 사용하고 동작을 체크해보겠습니다.

state = {
  transformAnimation: new Animated.Value(0),
  fallAnimation: new Animated.Value(0)
}

componentDidMount() {
  const transformToBallAnimation = Animated.timing(
    this.state.transformAnimation,
    {
      toValue: 50,
      duration: 1000
    }
  );

  const fallAnimation = Animated.timing(
    this.state.fallAnimation,
    {
      toValue: 250,
      duration: 3000,
      easing: Easing.bounce
    }
  );

  Animated.parallel([
    transformToBallAnimation,
    fallAnimation
  ]).start();
}

Parallel example

이번에는 상자가 움직이고 동시에 변형되기 시작합니다. 애니메이션이 끝날 무렵에 변형이 완료됩니다.

Source.

 

Delay

Sequence 애니메이션을 사용하는 사이에 Delay(지연)를 정의 할 수 있습니다.

state = {
  transformAnimation: new Animated.Value(0),
  fallAnimation: new Animated.Value(0)
}

componentDidMount() {
  const transformToBallAnimation = Animated.timing(
    this.state.transformAnimation,
    {
      toValue: 50,
      duration: 1000
    }
  );

  const fallAnimation = Animated.timing(
    this.state.fallAnimation,
    {
      toValue: 250,
      duration: 3000,
      easing: Easing.bounce
    }
  );

  Animated.sequence([
    transformToBallAnimation,
    Animated.delay(1000),
    fallAnimation
  ]).start();
}

예상대로 상자 변환을 마친 후 약간의 정지가 더해집니다.

Delay example

Source.

 

Stagger

때때로 우리는 Sequence와 Parallel 사이에 무언가가 필요할 수 있습니다. 애니메이션을 시작한 다음 첫 번째 애니메이션이 끝나기 전에 또 다른 애니메이션을 시작해야한다고 상상해보십시오.

이 동작을 이루기 위해 Animated.stagger 함수를 사용할 수 있습니다. 다음 애니메이션 및 애니메이션 목록을 시작하기 전에 지연을 허용합니다.

state = {
  transformAnimation: new Animated.Value(0),
  fallAnimation: new Animated.Value(0)
}

componentDidMount() {
  const transformToBallAnimation = Animated.timing(
    this.state.transformAnimation,
    {
      toValue: 50,
      duration: 1000
    }
  );

  const fallAnimation = Animated.timing(
    this.state.fallAnimation,
    {
      toValue: 250,
      duration: 3000,
      easing: Easing.bounce
    }
  );

  Animated.stagger(500, [
    transformToBallAnimation,
    fallAnimation
  ]).start();
}

이 경우 상자가 변형되기 시작하고 0.5초 후에 상자가 움직이기 시작합니다.

Stagger example

 

Wrapping up

오늘 우리는 timing, springdecay와 같은 다양한 애니메이션 유형을 다루었습니다. 우리는 애니메이션을 반복하고 easing functions를 적용하는 방법을 배웠습니다. 그런 다음 컴포지션 기능을 알아야합니다. 이러한 기능을 사용하여 애니메이션을 결합하여 병렬 또는 다른 순서로 실행할 수 있습니다.

좋은 지식 기반을 구축한다고 생각합니다. 이제 프로젝트에서 애니메이션 사용을 시작할 준비가되었습니다. 가서 사용해보십시오.

다음에 또 만나요. 이 모든 예제의 전체 코스 코드는 GitHub 페이지에서 찾을 수 있습니다.