Reanimated — 고성능 애니메이션 라이브러리
Reanimated는 UI 스레드에서 직접 애니메이션을 실행하여 Animated API보다 뛰어난 성능과 유연성을 제공합니다.
Animated API가 기본 애니메이션에 충분하다면, Reanimated는 복잡한 제스처 기반 인터랙션, 레이아웃 애니메이션, 조건부 애니메이션에 필요합니다.
설치
npm install react-native-reanimated
# babel.config.js에 플러그인 추가
module.exports = {
plugins: ['react-native-reanimated/plugin'],
};
핵심 개념: Shared Values와 Worklets
import Animated, {
useSharedValue,
useAnimatedStyle,
withTiming,
withSpring,
} from 'react-native-reanimated';
function BasicAnimation() {
// Shared Value — JS와 UI 스레드 간 공유되는 값
const offset = useSharedValue(0);
// Animated Style — UI 스레드에서 실행되는 스타일 계산
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ translateX: offset.value }],
}));
const moveRight = () => {
// withTiming — 시간 기반 애니메이션
offset.value = withTiming(200, { duration: 500 });
};
const moveBack = () => {
// withSpring — 스프링 물리 애니메이션
offset.value = withSpring(0);
};
return (
<View>
<Animated.View style={[styles.box, animatedStyle]} />
<Pressable onPress={moveRight}><Text>오른쪽</Text></Pressable>
<Pressable onPress={moveBack}><Text>되돌리기</Text></Pressable>
</View>
);
}
Animated API와 달리 Reanimated는
useRef로 값을 만들지 않고useSharedValue를 사용 합니다. 이 값은 UI 스레드에서 직접 읽고 쓸 수 있어 Bridge를 거치지 않습니다.
제스처 기반 애니메이션
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
} from 'react-native-reanimated';
function DraggableBox() {
const translateX = useSharedValue(0);
const translateY = useSharedValue(0);
const startX = useSharedValue(0);
const startY = useSharedValue(0);
const panGesture = Gesture.Pan()
.onBegin(() => {
startX.value = translateX.value;
startY.value = translateY.value;
})
.onUpdate((event) => {
translateX.value = startX.value + event.translationX;
translateY.value = startY.value + event.translationY;
})
.onEnd(() => {
// 손을 떼면 원래 위치로 돌아감
translateX.value = withSpring(0);
translateY.value = withSpring(0);
});
const animatedStyle = useAnimatedStyle(() => ({
transform: [
{ translateX: translateX.value },
{ translateY: translateY.value },
],
}));
return (
<GestureDetector gesture={panGesture}>
<Animated.View style={[styles.box, animatedStyle]} />
</GestureDetector>
);
}
Layout Animations
컴포넌트가 추가, 제거, 레이아웃이 변경될 때 자동 애니메이션을 적용합니다.
import Animated, {
FadeIn,
FadeOut,
SlideInRight,
SlideOutLeft,
Layout,
} from 'react-native-reanimated';
function AnimatedList() {
const [items, setItems] = useState<string[]>([]);
const addItem = () => {
setItems((prev) => [...prev, `아이템 ${prev.length + 1}`]);
};
const removeItem = (index: number) => {
setItems((prev) => prev.filter((_, i) => i !== index));
};
return (
<View>
<Pressable onPress={addItem}><Text>추가</Text></Pressable>
{items.map((item, index) => (
<Animated.View
key={item}
entering={SlideInRight.duration(300)} // 등장 애니메이션
exiting={SlideOutLeft.duration(200)} // 퇴장 애니메이션
layout={Layout.springify()} // 레이아웃 변경 애니메이션
style={styles.listItem}
>
<Text>{item}</Text>
<Pressable onPress={() => removeItem(index)}>
<Text>삭제</Text>
</Pressable>
</Animated.View>
))}
</View>
);
}
사용 가능한 Layout Animation
// 등장 (Entering)
FadeIn, FadeInDown, FadeInUp, FadeInLeft, FadeInRight
SlideInDown, SlideInUp, SlideInLeft, SlideInRight
ZoomIn, BounceIn, FlipInXDown, RotateInDownLeft
// 퇴장 (Exiting)
FadeOut, FadeOutDown, SlideOutLeft, ZoomOut, BounceOut
// 커스터마이징
FadeIn.duration(500).delay(200).springify()
SlideInRight.springify().damping(15)
Interpolation
import { interpolate, Extrapolation } from 'react-native-reanimated';
function ParallaxHeader() {
const scrollY = useSharedValue(0);
const headerStyle = useAnimatedStyle(() => ({
height: interpolate(
scrollY.value,
[0, 200],
[300, 80],
Extrapolation.CLAMP
),
opacity: interpolate(
scrollY.value,
[0, 150],
[1, 0],
Extrapolation.CLAMP
),
}));
return (
<>
<Animated.View style={[styles.header, headerStyle]}>
<Text>패럴랙스 헤더</Text>
</Animated.View>
<Animated.ScrollView
onScroll={useAnimatedScrollHandler({
onScroll: (event) => {
scrollY.value = event.contentOffset.y;
},
})}
scrollEventThrottle={16}
>
{/* 콘텐츠 */}
</Animated.ScrollView>
</>
);
}
Animated API vs Reanimated 비교
| 항목 | Animated API | Reanimated |
|---|---|---|
| 실행 위치 | 네이티브 드라이버 선택적 | 항상 UI 스레드 |
| 레이아웃 애니메이션 | 미지원 | 지원 |
| 제스처 연동 | 제한적 | Gesture Handler 통합 |
| 조건부 로직 | 불가 | worklet 내 if/else 가능 |
| 설치 | 내장 | 별도 설치 |
| 학습 곡선 | 낮음 | 중간 |
정리
- Reanimated는 UI 스레드에서 직접 애니메이션을 실행 하여 항상 60fps를 보장합니다
useSharedValue와useAnimatedStyle이 핵심 API입니다- Layout Animations 로 리스트 추가/삭제 시 자동 애니메이션을 적용할 수 있습니다
- Gesture Handler 와 결합하면 드래그, 스와이프 같은 복잡한 인터랙션을 구현할 수 있습니다
- 기본 애니메이션은 Animated API로 충분하지만, 복잡해지면 Reanimated가 필수입니다
댓글 로딩 중...