🎮 Animation Magic: Gestures & Reanimated in React Native
Imagine your phone screen is a magic sandbox. When you touch it, poke it, swipe it, or pinch it—things happen! That’s what we’re learning today: how to make your app feel alive by responding to your fingers like magic.
🧙♂️ The Story of Two Best Friends
Meet Gesture Handler and Reanimated. They’re best friends who work together to create smooth, buttery animations in your app.
-
Gesture Handler is like a super-sensitive detective 🔍 who watches your fingers and says, “Hey! The user just tapped here!” or “Look! They’re swiping left!”
-
Reanimated is like a magical artist 🎨 who takes that information and makes things move beautifully on screen—no stuttering, no lag, just smooth motion.
Together, they make your app feel like a living, breathing thing.
🔧 1. Gesture Handler Setup
What Is It?
Before we can detect finger touches, we need to install our detective! Gesture Handler needs to be set up properly so it can watch for all those taps, swipes, and pinches.
Simple Analogy
Think of it like setting up a security camera before you can see what’s happening in your house. No camera = no watching!
How to Set It Up
Step 1: Install the package
npm install react-native-gesture-handler
Step 2: Wrap your whole app with the magic wrapper
import { GestureHandlerRootView }
from 'react-native-gesture-handler';
export default function App() {
return (
<GestureHandlerRootView
style={{ flex: 1 }}>
{/* Your app goes here */}
</GestureHandlerRootView>
);
}
💡 Why This Matters
Without GestureHandlerRootView, gestures won’t work! It’s like trying to listen to music without speakers—nothing happens.
graph TD A["Your App"] --> B["GestureHandlerRootView"] B --> C["Now Gestures Work!"] B --> D["Detects Taps"] B --> E["Detects Swipes"] B --> F["Detects Pinches"]
✋ 2. Gesture Types
What Are They?
Just like there are different ways to knock on a door (tap, bang, scratch), there are different types of gestures your fingers can make!
The Main Gesture Types
| Gesture | What It Does | Real-Life Example |
|---|---|---|
| Tap | Quick touch | Pressing a doorbell 🔔 |
| Pan | Drag around | Moving a chess piece ♟️ |
| Pinch | Two fingers squeeze | Zooming a photo 📷 |
| Rotation | Two fingers twist | Turning a dial 🎛️ |
| LongPress | Hold down | Opening a secret menu 📜 |
| Fling | Quick swipe | Flicking away a card 🃏 |
Code Example: Tap Gesture
import { Gesture, GestureDetector }
from 'react-native-gesture-handler';
function MyButton() {
const tap = Gesture.Tap()
.onStart(() => {
console.log('You tapped me!');
});
return (
<GestureDetector gesture={tap}>
<View style={styles.button}>
<Text>Tap Me!</Text>
</View>
</GestureDetector>
);
}
Code Example: Pan Gesture (Dragging)
const pan = Gesture.Pan()
.onUpdate((event) => {
// event.translationX = how far
// you moved horizontally
// event.translationY = how far
// you moved vertically
console.log(
`Moved: ${event.translationX},
${event.translationY}`
);
});
🎯 Key Insight
Each gesture gives you different information:
- Tap tells you where you tapped
- Pan tells you how far you dragged
- Pinch tells you how much you squeezed
- Rotation tells you how much you rotated
🤝 3. Gesture Composition
What Is It?
Sometimes you want multiple gestures to work together! Like rubbing your tummy AND patting your head at the same time.
The Three Ways to Combine Gestures
graph TD A["Gesture Composition"] --> B["Simultaneous"] A --> C["Exclusive"] A --> D["Sequential"] B --> E["Both work at same time"] C --> F["Only one can win"] D --> G["One after another"]
1. Simultaneous (Both at Once)
Like walking and talking—you can do both!
const pinch = Gesture.Pinch();
const rotation = Gesture.Rotation();
// Both gestures work together
const combined = Gesture.Simultaneous(
pinch,
rotation
);
2. Exclusive (Only One Winner)
Like a race—only one person wins!
const tap = Gesture.Tap();
const longPress = Gesture.LongPress();
// If you hold long enough = longPress
// If you release quickly = tap
const combined = Gesture.Exclusive(
longPress,
tap
);
3. Sequential (One Then Another)
Like a recipe—step 1, then step 2!
const firstTap = Gesture.Tap();
const secondTap = Gesture.Tap();
// Must tap twice in a row
const doubleTap = Gesture.Sequence(
firstTap,
secondTap
);
💡 Real-World Example
Instagram photo viewer:
- Simultaneous: Pinch to zoom + Rotate together
- Exclusive: Single tap (show controls) vs Double tap (like photo)
💎 4. Shared Values
What Are They?
Here’s where the magic begins! Shared Values are special numbers that live on the “UI thread”—the super-fast highway where animations happen.
Simple Analogy
Imagine you have a magical notepad. When you write a number on it, your animation instantly sees the new number and updates—no waiting, no delay!
Regular variables are like sending a letter by mail ✉️—slow! Shared values are like telepathy 🧠—instant!
How to Create One
import { useSharedValue }
from 'react-native-reanimated';
function MyComponent() {
// Start at position 0
const translateX = useSharedValue(0);
// Change it anytime!
translateX.value = 100;
return <View />;
}
Shared Values in Gestures
const translateX = useSharedValue(0);
const translateY = useSharedValue(0);
const pan = Gesture.Pan()
.onUpdate((event) => {
// Update shared values as you drag
translateX.value = event.translationX;
translateY.value = event.translationY;
});
🚀 Why So Fast?
graph TD A["Your Finger Moves"] --> B["Gesture Detects"] B --> C["Shared Value Updates"] C --> D["Animation Shows Instantly"] D --> E["60 FPS Smooth!"]
Regular React state causes re-renders (slow). Shared values skip all that and go straight to the animation!
🎨 5. useAnimatedStyle
What Is It?
This is how you connect your shared values to actual styles! It’s like connecting a puppet’s strings to your fingers.
Simple Analogy
- Shared Value = Your hand position
- useAnimatedStyle = The string
- Animated.View = The puppet
When you move your hand, the puppet moves!
Basic Example
import Animated, {
useSharedValue,
useAnimatedStyle
} from 'react-native-reanimated';
function DraggableBox() {
const translateX = useSharedValue(0);
// This style AUTOMATICALLY updates
// when translateX.value changes!
const animatedStyle = useAnimatedStyle(
() => ({
transform: [
{ translateX: translateX.value }
],
})
);
return (
<Animated.View
style={[styles.box, animatedStyle]}
/>
);
}
🎯 Key Rules
- Always use
Animated.View, not regularView - Put your shared values inside
useAnimatedStyle - Return a style object from the function
- It updates automatically—no need to tell it!
Full Draggable Example
function DraggableBox() {
const translateX = useSharedValue(0);
const translateY = useSharedValue(0);
const pan = Gesture.Pan()
.onUpdate((e) => {
translateX.value = e.translationX;
translateY.value = e.translationY;
});
const animatedStyle = useAnimatedStyle(
() => ({
transform: [
{ translateX: translateX.value },
{ translateY: translateY.value },
],
})
);
return (
<GestureDetector gesture={pan}>
<Animated.View
style={[styles.box, animatedStyle]}
/>
</GestureDetector>
);
}
✨ 6. Reanimated Animations
What Are They?
So far, things move exactly where your finger goes. But what if you want things to spring, bounce, or glide smoothly? That’s where animation functions come in!
The Three Animation Types
| Type | How It Feels | Use Case |
|---|---|---|
withTiming |
Smooth and predictable | Fading, sliding |
withSpring |
Bouncy and natural | Buttons, cards |
withDecay |
Keeps going, then stops | Scrolling, flicking |
withTiming (Smooth Transition)
import { withTiming }
from 'react-native-reanimated';
// Move to position 200 over 500ms
translateX.value = withTiming(200, {
duration: 500,
});
withSpring (Bouncy Fun!)
import { withSpring }
from 'react-native-reanimated';
// Bounce to position 200
translateX.value = withSpring(200, {
damping: 10, // Less = more bouncy
stiffness: 100, // More = faster
});
withDecay (Momentum)
import { withDecay }
from 'react-native-reanimated';
// Continue moving based on velocity
pan.onEnd((e) => {
translateX.value = withDecay({
velocity: e.velocityX, // How fast
deceleration: 0.998, // Friction
});
});
Complete Example: Swipe Card
function SwipeCard() {
const translateX = useSharedValue(0);
const pan = Gesture.Pan()
.onUpdate((e) => {
// Follow finger exactly
translateX.value = e.translationX;
})
.onEnd(() => {
// Spring back to center!
translateX.value = withSpring(0);
});
const style = useAnimatedStyle(() => ({
transform: [
{ translateX: translateX.value }
],
}));
return (
<GestureDetector gesture={pan}>
<Animated.View style={[
styles.card,
style
]} />
</GestureDetector>
);
}
graph TD A["Finger Drags"] --> B["onUpdate"] B --> C["translateX = finger position"] A --> D["Finger Releases"] D --> E["onEnd"] E --> F["withSpring back to 0"] F --> G["Card bounces back!"]
🎓 Putting It All Together
Here’s everything working together:
import {
Gesture,
GestureDetector,
GestureHandlerRootView
} from 'react-native-gesture-handler';
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
} from 'react-native-reanimated';
function App() {
const translateX = useSharedValue(0);
const translateY = useSharedValue(0);
const scale = useSharedValue(1);
const pan = Gesture.Pan()
.onUpdate((e) => {
translateX.value = e.translationX;
translateY.value = e.translationY;
})
.onEnd(() => {
translateX.value = withSpring(0);
translateY.value = withSpring(0);
});
const pinch = Gesture.Pinch()
.onUpdate((e) => {
scale.value = e.scale;
})
.onEnd(() => {
scale.value = withSpring(1);
});
const combined = Gesture.Simultaneous(
pan,
pinch
);
const style = useAnimatedStyle(() => ({
transform: [
{ translateX: translateX.value },
{ translateY: translateY.value },
{ scale: scale.value },
],
}));
return (
<GestureHandlerRootView
style={{ flex: 1 }}>
<GestureDetector gesture={combined}>
<Animated.View
style={[styles.box, style]}
/>
</GestureDetector>
</GestureHandlerRootView>
);
}
🌟 Summary
| Concept | What It Does | Remember It As |
|---|---|---|
| Gesture Handler Setup | Enables gesture detection | Install the detective |
| Gesture Types | Different finger actions | Tap, Pan, Pinch, etc. |
| Gesture Composition | Combine multiple gestures | Teamwork makes dream work |
| Shared Values | Super-fast animation data | Telepathic numbers |
| useAnimatedStyle | Connect values to styles | Puppet strings |
| Reanimated Animations | Add physics and timing | withSpring, withTiming |
🚀 You Did It!
You now understand how to make your React Native app respond to touch like a professional app!
Remember:
- Set up Gesture Handler first
- Choose the right gesture type
- Combine them if needed
- Store values in shared values
- Connect with useAnimatedStyle
- Animate with withSpring/withTiming
Go make something amazing! 🎉
