Skip to main content

애니메이션

Animated 라이브러리는 애니메이션을 유연하고 강력하게 만들며, 구축과 유지보수를 간편하게 하는 데 초점을 맞춘다. Animated는 입력과 출력 간의 선언적 관계, 그 사이에 설정 가능한 변환, 그리고 시간 기반 애니메이션 실행을 제어하는 start/stop 메서드에 주력한다.

애니메이션을 생성하는 핵심 워크플로는 Animated.Value를 생성하고, 이를 애니메이션 컴포넌트의 하나 이상의 스타일 속성에 연결한 다음, Animated.timing()을 사용해 애니메이션을 통해 업데이트를 주도하는 것이다.

애니메이션 값을 직접 수정하지 않는다. useRef Hook을 사용해 변경 가능한 ref 객체를 반환할 수 있다. 이 ref 객체의 current 프로퍼티는 주어진 인자로 초기화되며, 컴포넌트 생명주기 동안 유지된다.

예제

다음 예제는 애니메이션 값 fadeAnim에 따라 페이드 인과 페이드 아웃 효과를 적용하는 View를 보여준다.

Animated를 활용한 추가 예제는 애니메이션 가이드를 참고한다.

개요

Animated와 함께 사용할 수 있는 값 타입은 두 가지다:

Animated.Value는 스타일 속성이나 다른 props에 바인딩할 수 있으며, 보간(interpolation)도 가능하다. 하나의 Animated.Value로 여러 속성을 제어할 수 있다.

애니메이션 설정하기

Animated는 세 가지 유형의 애니메이션을 제공한다. 각 애니메이션 유형은 초기값에서 최종값까지 어떻게 변화할지 제어하는 특정 애니메이션 곡선을 제공한다:

대부분의 경우 timing()을 사용하게 된다. 기본적으로 이 함수는 대칭적인 easeInOut 곡선을 사용해, 객체가 점차 가속한 후 다시 점차 감속하며 멈추는 효과를 만든다.

애니메이션 작업하기

애니메이션은 start()를 호출해 시작한다. start()는 애니메이션이 완료될 때 실행될 콜백 함수를 인자로 받는다. 애니메이션이 정상적으로 완료되면 콜백 함수는 {finished: true}와 함께 호출된다. 만약 애니메이션이 완료되기 전에 stop()이 호출되어 중단된 경우(예: 제스처나 다른 애니메이션에 의해 중단된 경우), 콜백 함수는 {finished: false}를 받는다.

tsx
Animated.timing({}).start(({finished}) => {
/* 완료 콜백 */
});

네이티브 드라이버를 사용하면 애니메이션을 시작하기 전에 애니메이션 관련 모든 정보를 네이티브로 전송한다. 이렇게 하면 네이티브 코드가 UI 스레드에서 애니메이션을 수행할 수 있으며, 매 프레임마다 브릿지를 거칠 필요가 없다. 애니메이션이 시작된 후에는 JS 스레드가 블로킹되더라도 애니메이션에 영향을 미치지 않는다.

애니메이션 설정에서 useNativeDriver: true를 지정해 네이티브 드라이버를 사용할 수 있다. 자세한 내용은 애니메이션 가이드를 참고한다.

애니메이션 가능한 컴포넌트

애니메이션 가능한 컴포넌트만 애니메이션을 적용할 수 있다. 이러한 특수한 컴포넌트는 애니메이션 값을 속성에 바인딩하는 마법 같은 작업을 수행하며, 매 프레임마다 React의 렌더링과 조정 과정을 거치지 않고도 타겟팅된 네이티브 업데이트를 실행한다. 또한 언마운트 시 자동으로 정리 작업을 처리하므로 기본적으로 안전하다.

Animated는 위의 래퍼를 사용해 다음과 같은 애니메이션 가능한 컴포넌트를 제공한다:

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

애니메이션 합성하기

애니메이션은 합성 함수를 사용해 복잡한 방식으로 조합할 수 있다:

  • Animated.delay()는 주어진 지연 시간 후에 애니메이션을 시작한다.
  • Animated.parallel()은 여러 애니메이션을 동시에 시작한다.
  • Animated.sequence()는 애니메이션을 순서대로 시작하고, 각 애니메이션이 완료된 후에 다음 애니메이션을 시작한다.
  • Animated.stagger()는 애니메이션을 순서대로 시작하지만, 연속적인 지연 시간을 두고 병렬로 실행한다.

또한, 하나의 애니메이션의 toValue를 다른 Animated.Value로 설정해 애니메이션을 연결할 수도 있다. 자세한 내용은 Animations 가이드에서 동적 값 추적을 참고한다.

기본적으로 하나의 애니메이션이 중단되거나 중지되면, 그룹 내의 다른 모든 애니메이션도 중지된다.

애니메이션 값 결합하기

두 애니메이션 값을 더하거나, 빼거나, 곱하거나, 나누거나, 나머지 연산을 통해 새로운 애니메이션 값을 만들 수 있다:

보간(Interpolation)

interpolate() 함수는 입력 범위를 다양한 출력 범위로 매핑할 수 있게 해준다. 기본적으로 주어진 범위를 넘어서도 곡선을 외삽하지만, 출력 값을 고정하도록 설정할 수도 있다. 기본적으로 선형 보간을 사용하지만, easing 함수도 지원한다.

애니메이션 가이드에서 보간에 대해 더 자세히 알아볼 수 있다.

제스처 및 이벤트 처리

패닝이나 스크롤링과 같은 제스처 및 기타 이벤트는 Animated.event()를 사용해 애니메이션 값에 직접 매핑할 수 있다. 이때 구조화된 맵 구문을 사용해 복잡한 이벤트 객체에서 값을 추출한다. 첫 번째 레벨은 여러 인자를 매핑할 수 있도록 배열로 구성되며, 이 배열은 중첩된 객체를 포함한다.

예를 들어, 가로 스크롤 제스처를 처리할 때 event.nativeEvent.contentOffset.xscrollX(Animated.Value)에 매핑하려면 다음과 같이 작성한다:

tsx
 onScroll={Animated.event(
// scrollX = e.nativeEvent.contentOffset.x
[{nativeEvent: {
contentOffset: {
x: scrollX
}
}
}]
)}

참고 자료

메서드

주어진 값이 Value 대신 ValueXY 타입일 때, 각 설정 옵션은 스칼라 값 대신 {x: ..., y: ...} 형태의 벡터로 표현될 수 있다.

decay()

tsx
static decay(value, config): CompositeAnimation;

초기 속도에서 감쇠 계수에 따라 점점 속도가 줄어들며 애니메이션을 적용한다.

config는 다음과 같은 옵션을 가진 객체다:

  • velocity: 초기 속도. 필수 값이다.
  • deceleration: 감쇠율. 기본값은 0.997이다.
  • isInteraction: 이 애니메이션이 InteractionManager에 "상호작용 핸들"을 생성하는지 여부. 기본값은 true이다.
  • useNativeDriver: true일 경우 네이티브 드라이버를 사용한다. 필수 값이다.

timing()

tsx
static timing(value, config): CompositeAnimation;

특정 시간 동안 이징 곡선을 따라 값을 애니메이션화한다. Easing 모듈에는 다양한 미리 정의된 곡선이 있지만, 직접 만든 함수를 사용할 수도 있다.

config는 다음과 같은 옵션을 가질 수 있는 객체다:

  • duration: 애니메이션 지속 시간(밀리초). 기본값은 500이다.
  • easing: 곡선을 정의하는 이징 함수. 기본값은 Easing.inOut(Easing.ease)이다.
  • delay: 애니메이션 시작 전 지연 시간(밀리초). 기본값은 0이다.
  • isInteraction: 이 애니메이션이 InteractionManager에 "interaction handle"을 생성하는지 여부. 기본값은 true이다.
  • useNativeDriver: true일 경우 네이티브 드라이버를 사용한다. 필수 항목이다.

spring()

tsx
static spring(value, config): CompositeAnimation;

spring()감쇠 조화 진동을 기반으로 한 분석적 스프링 모델에 따라 값을 애니메이션화한다. toValue가 업데이트될 때 유연한 움직임을 만들기 위해 속도 상태를 추적하며, 여러 애니메이션을 연결할 수 있다.

config는 다음과 같은 옵션을 가질 수 있는 객체다.

단, bounciness/speed, tension/friction, 또는 stiffness/damping/mass 중 하나만 정의할 수 있으며, 둘 이상을 동시에 정의할 수 없다는 점에 유의해야 한다.

friction/tension 또는 bounciness/speed 옵션은 Facebook Pop, Rebound, 그리고 Origami의 스프링 모델과 일치한다.

  • friction: "튕김" 또는 오버슈트를 제어한다. 기본값은 7이다.
  • tension: 애니메이션 속도를 제어한다. 기본값은 40이다.
  • speed: 애니메이션 속도를 제어한다. 기본값은 12이다.
  • bounciness: 튕김 정도를 제어한다. 기본값은 8이다.

stiffness/damping/mass를 매개변수로 지정하면 Animated.spring감쇠 조화 진동의 운동 방정식을 기반으로 한 분석적 스프링 모델을 사용한다. 이 동작은 스프링 역학의 물리적 원리를 더 정확하고 충실하게 따르며, iOS의 CASpringAnimation 구현과 매우 유사하다.

  • stiffness: 스프링의 강성 계수다. 기본값은 100이다.
  • damping: 마찰력으로 인해 스프링의 움직임이 어떻게 감쇠되어야 하는지 정의한다. 기본값은 10이다.
  • mass: 스프링 끝에 부착된 물체의 질량이다. 기본값은 1이다.

다른 구성 옵션은 다음과 같다:

  • velocity: 스프링에 부착된 물체의 초기 속도다. 기본값은 0(정지 상태)이다.
  • overshootClamping: 스프링이 튕기지 않고 고정되어야 하는지 여부를 나타내는 불리언 값이다. 기본값은 false다.
  • restDisplacementThreshold: 스프링이 정지 상태로 간주되어야 하는 변위 임계값이다. 기본값은 0.001이다.
  • restSpeedThreshold: 스프링이 정지 상태로 간주되어야 하는 속도(초당 픽셀 단위)다. 기본값은 0.001이다.
  • delay: 애니메이션 시작 전 지연 시간(밀리초)이다. 기본값은 0이다.
  • isInteraction: 이 애니메이션이 InteractionManager에 "interaction handle"을 생성하는지 여부다. 기본값은 true이다.
  • useNativeDriver: true일 경우 네이티브 드라이버를 사용한다. 필수 옵션이다.

add()

tsx
static add(a: Animated, b: Animated): AnimatedAddition;

두 Animated 값을 더한 결과로 새로운 Animated 값을 생성한다.

subtract()

tsx
static subtract(a: Animated, b: Animated): AnimatedSubtraction;

첫 번째 Animated 값에서 두 번째 Animated 값을 뺀 새로운 Animated 값을 생성한다.

divide()

tsx
static divide(a: Animated, b: Animated): AnimatedDivision;

첫 번째 Animated 값을 두 번째 Animated 값으로 나눈 결과로 새로운 Animated 값을 생성한다.

multiply()

tsx
static multiply(a: Animated, b: Animated): AnimatedMultiplication;

두 Animated 값을 곱한 결과로 새로운 Animated 값을 생성한다.

modulo()

tsx
static modulo(a: Animated, modulus: number): AnimatedModulo;

제공된 Animated 값의 (음수가 아닌) 모듈로를 계산하여 새로운 Animated 값을 생성한다.

diffClamp()

tsx
static diffClamp(a: Animated, min: number, max: number): AnimatedDiffClamp;

두 값 사이로 제한된 새로운 Animated 값을 생성한다. 이 함수는 마지막 값과의 차이를 사용하기 때문에, 값이 범위에서 멀리 떨어져 있어도 다시 가까워지기 시작하면 값이 변하기 시작한다. (value = clamp(value + diff, min, max)).

이 기능은 스크롤 이벤트와 함께 사용할 때 유용하다. 예를 들어, 위로 스크롤할 때 네비게이션 바를 보여주고, 아래로 스크롤할 때 숨기는 데 활용할 수 있다.

delay()

tsx
static delay(time: number): CompositeAnimation;

주어진 지연 시간 이후에 애니메이션을 시작한다.

sequence()

tsx
static sequence(animations: CompositeAnimation[]): CompositeAnimation;

여러 애니메이션을 순서대로 시작한다. 각 애니메이션이 완료된 후에 다음 애니메이션을 시작한다. 현재 실행 중인 애니메이션이 중단되면, 이후 애니메이션은 시작되지 않는다.

parallel()

tsx
static parallel(
animations: CompositeAnimation[],
config?: ParallelConfig
): CompositeAnimation;

여러 애니메이션을 동시에 시작한다. 기본적으로 하나의 애니메이션이 중지되면 모든 애니메이션이 중지된다. 이 동작은 stopTogether 플래그를 통해 변경할 수 있다.

stagger()

tsx
static stagger(
time: number,
animations: CompositeAnimation[]
): CompositeAnimation;

여러 애니메이션을 배열로 전달하면, 이 애니메이션들은 병렬로 실행될 수 있지만, 순차적으로 시작되며 각각의 시작 사이에 지정된 시간만큼의 지연이 발생한다. 이 기능은 연속적인 효과를 구현할 때 유용하다.

loop()

tsx
static loop(
animation: CompositeAnimation[],
config?: LoopAnimationConfig
): CompositeAnimation;

주어진 애니메이션을 연속적으로 반복한다. 애니메이션이 끝에 도달할 때마다 초기 상태로 돌아가 다시 시작한다. 자식 애니메이션이 useNativeDriver: true로 설정된 경우 JS 스레드를 블로킹하지 않고 루프를 실행한다. 또한, 애니메이션이 실행되는 동안 VirtualizedList 기반 컴포넌트가 추가 행을 렌더링하지 못하도록 방지할 수 있다. 이 문제를 해결하려면 자식 애니메이션 설정에서 isInteraction: false를 전달하면 된다.

config는 다음과 같은 옵션을 가질 수 있는 객체이다:

  • iterations: 애니메이션이 반복되어야 하는 횟수. 기본값은 -1 (무한 반복).

event()

tsx
static event(
argMapping: Mapping[],
config?: EventConfig
): (...args: any[]) => void;

매핑 배열을 받아 각 인자에서 값을 추출한 후, 매핑된 출력에 대해 setValue를 호출한다. 예를 들면:

tsx
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {x: this._scrollX}}}],
{listener: (event: ScrollEvent) => console.log(event)}, // 선택적 비동기 리스너
)}
...
onPanResponderMove: Animated.event(
[
null, // 원시 이벤트 인자는 무시
{dx: this._panX},
], // 제스처 상태 인자
{
listener: (
event: GestureResponderEvent,
gestureState: PanResponderGestureState
) => console.log(event, gestureState),
} // 선택적 비동기 리스너
);

config는 다음과 같은 옵션을 가질 수 있는 객체이다:

  • listener: 선택적 비동기 리스너.
  • useNativeDriver: true일 경우 네이티브 드라이버를 사용한다. 필수.

forkEvent()

jsx
static forkEvent(event: AnimatedEvent, listener: Function): AnimatedEvent;

forkEvent()는 props를 통해 전달되는 애니메이션 이벤트를 감시하기 위한 고급 명령형 API다. 기존 AnimatedEvent에 새로운 자바스크립트 리스너를 추가할 수 있게 해준다. animatedEvent가 자바스크립트 리스너일 경우, 두 리스너를 하나로 합친다. animatedEvent가 null이나 undefined일 경우, 자바스크립트 리스너를 직접 할당한다. 가능한 경우 값을 직접 사용한다.

unforkEvent()

jsx
static unforkEvent(event: AnimatedEvent, listener: Function);

start()

tsx
static start(callback?: (result: {finished: boolean}) => void);

애니메이션은 start() 메서드를 호출해 시작한다. start()는 애니메이션이 완료되거나, 완료되기 전에 stop()이 호출되어 중단될 때 실행되는 완료 콜백 함수를 인자로 받는다.

매개변수:

이름타입필수 여부설명
callback(result: {finished: boolean}) => void아니오애니메이션이 정상적으로 완료되거나, 완료되기 전에 stop()이 호출되어 중단될 때 실행되는 함수

콜백 함수를 사용한 start() 예제:

tsx
Animated.timing({}).start(({finished}) => {
/* 완료 콜백 */
});

stop()

tsx
static stop();

실행 중인 애니메이션을 중지한다.

reset()

tsx
static reset();

실행 중인 애니메이션을 중지하고 값을 원래 상태로 초기화한다.

속성

Value

애니메이션을 제어하기 위한 표준 값 클래스이다. 일반적으로 useAnimatedValue(0); 또는 클래스 컴포넌트에서 new Animated.Value(0);로 초기화한다.

Animated.Value API에 대해 더 자세히 알고 싶다면 별도의 페이지를 참고한다.

ValueXY

2D 애니메이션(예: 패닝 제스처)을 제어하기 위한 2차원 값 클래스이다.

Animated.ValueXY API에 대한 자세한 내용은 별도의 페이지에서 확인할 수 있다.

Interpolation

Flow에서 Interpolation 타입을 사용하기 위해 내보낸다.

Node

타입 체크를 편리하게 하기 위해 내보낸 클래스이다. 모든 애니메이션 값은 이 클래스에서 파생된다.

createAnimatedComponent

React 컴포넌트를 애니메이션 가능하게 만드는 함수. Animated.View 등을 생성하는 데 사용한다.

attachNativeEvent

뷰의 이벤트에 애니메이션 값을 연결하기 위한 명령형 API다. 가능하다면 useNativeDriver: true와 함께 Animated.event를 사용하는 것을 권장한다.