프로젝트를 진행하며 기능 완성이 어느정도 끝나고 애니메이션을 적용하려고하니
RN에서 애니메이션을 사용한적이 꽤 오래되어서 다시 공부할겸 정리한다.
프로젝트에서 사용한 내용만을 정리했으며 더 자세한 내용은 공식문서 🌐을 참조
애니메이션에서 사용할 값은 new Animated.Value(기본값)
을 사용해서 선언한다.
const animatedValue = useRef(new Animated.Value(1)).current;
이때 useRef
를 사용하는 이유는 컴포넌트의 라이프사이클 동안 값을 유지하기 위해서이다. 즉 컴포넌트가 다시 렌더링될때 animatedValue를 유지해주기 위해서이다.
const animatedValue = new Animated.Value(1);
useRef 없이 위처럼 사용시 컴포넌트가 렌더링되면 animatedValue의 값이 다시 1로 바뀌어 애니메이션이 유지되지 않거나 처음부터 다시 실행되버리는 문제가 발생한다.
위의 animatedValue
는 직접 수정하면 안된다.
공식 문서에서도 나와있듯이 Value는 직접 수정하지 말고 Animated의 메소드를 사용해서 애니메이션을 적용한다.
위의 컴포넌트들은 아래와 같이 사용해서 애니메이션 적용가능
<Animated.View>{chilren}</Animated.View>
위에 없는 컴포넌트들은 createAnimatedComponent()
를 사용해서 애니메이터블한 컴포넌트로 생성 가능
const Box = styled(Animated.createAnimatedComponent(View))``
이때 View를 react-native에서 import 해와야한다.
const Box = styled.TouchableOpacity``
const AnimatedBox = Animated.createAnimatedComponent(Box)``
생성되는 것은 확인했으나 eslint 문제인지, typescript 문제인지 prop 값들을 잘 못 읽는 문제가 발생했다.
애니메이션을 적용하기 위해 decay, spring, timing
메소드를 사용할 수 있다. 자세한 내용은 공식 문서를 참고하고 timing, sequence, loop
만 작성
static timing(value, config): CompositeAnimation;
시간에 따른 이벤트를 적용할때 사용하는 메소드
timing의 config의 속성은 다음과 같다
Easing.inOut
Animated.timing(animatedValue, {
toValue: 1.5,
duration: 1500,
useNativeDriver: false,
}),
static sequence(animations: CompositeAnimation[]): CompositeAnimation;
주어진 애니메이션을 순서대로 수행하는 메소드
Animated.sequence([
Animated.timing(animatedValue, {
toValue: 1.5, // Set the end value of the first part of your sequence
duration: 1500, // Duration of the first part of your sequence
useNativeDriver: false,
}),
Animated.timing(animatedValue, {
toValue: 1, // Reset to initial scale
duration: 1500, // Duration of the second part of your sequence
useNativeDriver: false,
}),
])
static loop(
animation: CompositeAnimation[],
config?: LoopAnimationConfig
): CompositeAnimation;
주어진 애니메이션을 게속해서 실행하는 메소드
Animated.loop(
Animated.sequence([
Animated.timing(animatedValue, {
toValue: 1.5, // Set the end value of the first part of your sequence
duration: 1500, // Duration of the first part of your sequence
useNativeDriver: false,
}),
Animated.timing(animatedValue, {
toValue: 1, // Reset to initial scale
duration: 1500, // Duration of the second part of your sequence
useNativeDriver: false,
}),
])
).start()
static start(callback?: (result: {finished: boolean}) => void);
애니메이션은 반드시 start 메소드를 사용해야 적용된다.
만약 컴포넌트의 사이즈가 1에서 2로 바뀔때 컬러를 바꾸고 싶다면 parallel
메소드로 여러 애니메이션을 동시에 실행시켜 바꾸게 할 수도 있지만 interpolation
을 이용하면 더 간단하고 예측가능한 코드를 작성할 수 있다.
Interpolation의 자세한 설명은 Interpolation with React Native Animations 글에서 자세히 되어있다.
요약하면 Animated.Value
의 범위에 종속적으로 값이 변하는 값을 만드는 기능이다.
const animatedValue = useRef(new Animated.Value(1)).current;
const backgroundColorOfComponent = animatedValue.interpolate({
inputRange: [1, 1.5], // animatedValue가 timing메소드의 config toValue 값으로 바뀌는 범위
outputRange: ["orange", "blue"] // animatedValue가 1일때 "orange", 1.5 일때 "blue" 1과 1.5 사이로 값이 움직일때 backgroundColorOfComponent 의 값은 "orange" 와 "blue" 사이에서 자동으로 변함
});