Explore the powerful capabilities of React Native Reanimated: smooth and complex animations, manage gestures, and enhance your user interface with movement, text animations, keyframes, and scroll-triggered effects
React Native Reanimated is a powerful library for creating smooth and complex animations in React Native applications. It uses native threads for performance, providing a declarative API for animations and gestures. Here, we will explore various features and functionalities of React Native Reanimated, and I will offer detailed explanations and examples.
Reanimated 3 is the latest version of the React Native Reanimated library, offering enhanced performance, new features, and improved ease of use for creating complex animations in React Native applications.
Core to Reanimated, shared values allow you to define and animate state variables that run on the UI thread for better performance.
const offsetX = useSharedValue(0);
Hooks like useAnimatedStyle
enable you to create styles that update automatically in response to shared value changes.
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ translateX: offsetX.value }],
}));
Seamless integration with react-native-gesture-handler allows for creating complex gesture-driven animations.
const gesture = Gesture.Pan().onUpdate((event) => {
offsetX.value = event.translationX;
});
New and improved functions like withSpring
, withTiming
, and withDecay
offer a variety of ways to animate properties.
offsetX.value = withSpring(100);
This example demonstrates the basic use of React Native Reanimated for animating elements along the x and y axes. This component provides interactive buttons to move a square element in different directions using spring animations. Here’s a detailed breakdown of its functionality and implementation.
useSharedValue
is used to create shared values (offsetX
and offsetY
) which represent the x and y positions of the animated element. These values are essential for tracking and updating the element's position during animations.useAnimatedStyle
creates an animated style that updates based on the shared values. The style transforms the element by translating it along the x and y axes according to offsetX
and offsetY
.withSpring
function is used to animate the shared values with a spring effect, providing a smooth and natural animation.These lines initialize the shared valuesconst offsetX = useSharedValue(0);
const offsetY = useSharedValue(0);
offsetX
and offsetY
to zero.const animatedStyles = useAnimatedStyle(() => {
return {
transform: [{ translateX: offsetX.value }, { translateY: offsetY.value }],
};
});
This hook creates an animated style that updates the element's transform property based on the current values of offsetX
and offsetY
.const getRandomSign = () => {
return Math.random() < 0.5 ? -1 : 1;
};
const resetAnimation = () => {
offsetX.value = withSpring(0);
offsetY.value = withSpring(0);
};
return (
<AnimationContainer resetAnimation={resetAnimation} title="X & Y Animations">
<Animated.View
style={[
animatedElementStyle,
animatedStyles,
{ width: 40, height: 40 },
]}
/>
<Flex style={{ gap: 20 }}>
<MyButton
text="Move Y"
onPress={() => {
offsetY.value = withSpring(Math.random() * -200);
}}
/>
<MyButton
text="Move X"
onPress={() => {
const randomValue = Math.random() * 200;
const randomSign = getRandomSign();
offsetX.value = withSpring(randomValue * randomSign);
}}
/>
<MyButton
text="Move X & Y"
onPress={() => {
const randomValueX = Math.random() * 200;
const randomValueY = Math.random() * -200;
const randomSignX = getRandomSign();
const randomSignY = getRandomSign();
offsetX.value = withSpring(randomValueX * randomSignX);
offsetY.value = withSpring(randomValueY * randomSignY);
}}
/>
</Flex>
</AnimationContainer>
);
The component renders an animated view styled with both static and animated styles, representing a square that moves based on user interactions.Example Two showcases the use of React Native Reanimated for creating timed animations. This component allows an element to move along the x-axis with a smooth timing animation when a button is pressed. Here’s a detailed breakdown of its functionality and implementation.
useSharedValue
is used to create a shared value (offset
) which represents the x position of the animated element. This value is essential for tracking and updating the element's position during animations.useAnimatedStyle
creates an animated style that updates based on the shared value. The style transforms the element by translating it along the x-axis according to offset
.withTiming
function is used to animate the shared value with a timed effect, providing a smooth and controlled animation.const offset = useSharedValue(-150);
This line initializes the shared value offset
to -150.const animatedStyles = useAnimatedStyle(() => {
return {
transform: [{ translateX: offset.value }],
};
});
This hook creates an animated style that updates the element's transform property based on the current value of offset
.const resetAnimation = () => {
offset.value = -150;
};
return (
<AnimationContainer resetAnimation={resetAnimation} height={screenHeight * 0.25} title="Animation with Timing">
<Animated.View
style={[
animatedStyles,
animatedElementStyle,
{ width: 80, height: 80 },
]}
/>
<MyButton
text="Move with Timing"
onPress={() => {
offset.value = withTiming(400, { duration: 1000 });
}}
/>
</AnimationContainer>
);
The component renders an animated view styled with both static and animated styles, representing a rectangle that moves based on user interactions.Gestures play a crucial role in creating interactive and responsive UIs. React Native Reanimated, combined with react-native-gesture-handler, allows for complex gesture-based animations.
Example Three demonstrates the use of React Native Reanimated in combination with gesture handling to create interactive animations. This component allows an element to be dragged around the screen, snapping back to its original position with a spring animation when released. Here’s a detailed breakdown of its functionality and implementation.
useSharedValue
is used to create shared values (offsetX
, offsetY
, startX
, and startY
) which represent the x and y positions of the animated element. These values are essential for tracking and updating the element's position during gestures.useAnimatedStyle
creates an animated style that updates based on the shared values. The style transforms the element by translating it along the x and y axes according to offsetX
and offsetY
.Gesture
API from react-native-gesture-handler
is used to handle pan gestures, allowing the element to be dragged around the screen.withSpring
function is used to animate the shared values with a spring effect, providing a smooth and natural animation when the gesture ends.const offsetX = useSharedValue(0);
const offsetY = useSharedValue(0);
const startX = useSharedValue(0);
const startY = useSharedValue(0);
These lines initialize the shared values to zero.const animatedStyles = useAnimatedStyle(() => {
return {
transform: [{ translateX: offsetX.value }, { translateY: offsetY.value }],
};
});
This hook creates an animated style that updates the element's transform property based on the current values of offsetX
and offsetY
.Gesture.Pan()
API to handle drag gestures.const gesture = Gesture.Pan()
.onStart(() => {
cancelAnimation(offsetX);
cancelAnimation(offsetY);
startX.value = offsetX.value;
startY.value = offsetY.value;
})
.onUpdate((event) => {
offsetX.value = startX.value + event.translationX;
offsetY.value = startY.value + event.translationY;
})
.onEnd(() => {
offsetX.value = withSpring(0);
offsetY.value = withSpring(0);
});
offsetX
and offsetY
values based on the gesture's translation.return (
<AnimationContainer title="Spring Physics Gesture" headingLight>
<FlexFull style={{ height: "100%", justifyContent: "center", alignItems: "center" }}>
<GestureDetector gesture={gesture}>
<Animated.View
style={[
animatedStyles,
elementStyleTwo,
{ width: 60, height: 60, justifyContent: "center" },
]}
>
<TextXs style={{ textAlign: "center", fontWeight: 600 }}>Drag Me</TextXs>
</Animated.View>
</GestureDetector>
</FlexFull>
</AnimationContainer>
);
The component renders an animated view styled with both static and animated styles, representing a draggable element. The text inside the element indicates that it can be dragged.Example Four demonstrates the use of React Native Reanimated in combination with gesture handling to create interactive animations. This component allows an element to be dragged around the screen and flung with a decay animation when released. Here’s a detailed breakdown of its functionality and implementation.
useSharedValue
is used to create shared values (offsetX
, offsetY
, startX
, and startY
) which represent the x and y positions of the animated element. These values are essential for tracking and updating the element's position during gestures.useAnimatedStyle
creates an animated style that updates based on the shared values. The style transforms the element by translating it along the x and y axes according to offsetX
and offsetY
.Gesture
API from react-native-gesture-handler
is used to handle pan gestures, allowing the element to be dragged around the screen.withDecay
function is used to animate the shared values with a decay effect, providing a smooth and natural animation when the gesture ends.const offsetX = useSharedValue(0);
const offsetY = useSharedValue(0);
const startX = useSharedValue(0);
const startY = useSharedValue(0);
These lines initialize the shared values to zero.const animatedStyles = useAnimatedStyle(() => {
return {
transform: [{ translateX: offsetX.value }, { translateY: offsetY.value }],
};
});
This hook creates an animated style that updates the element's transform property based on the current values of offsetX
and offsetY
.Gesture.Pan()
API to handle drag gestures.const gesture = Gesture.Pan()
.onStart(() => {
cancelAnimation(offsetX);
cancelAnimation(offsetY);
startX.value = offsetX.value;
startY.value = offsetY.value;
})
.onUpdate((event) => {
offsetX.value = startX.value + event.translationX;
offsetY.value = startY.value + event.translationY;
})
.onEnd((event) => {
offsetX.value = withDecay({
velocity: event.velocityX,
deceleration: 0.998,
});
offsetY.value = withDecay({
velocity: event.velocityY,
deceleration: 0.998,
});
});
offsetX
and offsetY
values based on the gesture's translation.const resetAnimation = () => {
offsetX.value = 0;
offsetY.value = 0;
};
return (
<AnimationContainer resetAnimation={resetAnimation} title="Gesture Handling with Decay" headingLight>
<FlexFull style={{ height: "100%", justifyContent: "center", alignItems: "center" }}>
<GestureDetector gesture={gesture}>
<Animated.View
style={[
animatedStyles,
elementStyleTwo,
{ width: 60, height: 60, justifyContent: "center" },
]}
>
<TextXs style={{ textAlign: "center", fontWeight: 600 }}>Fling Me</TextXs>
</Animated.View>
</GestureDetector>
</FlexFull>
</AnimationContainer>
);
The component renders an animated view styled with both static and animated styles, representing a draggable element. The text inside the element indicates that it can be flung.Example Five demonstrates the use of React Native Reanimated in combination with gesture handling to create interactive animations. This component allows an element to be dragged and scaled using pan and pinch gestures, respectively. Here’s a detailed breakdown of its functionality and implementation.
useSharedValue
is used to create shared values (offsetX
, offsetY
, scale
, startX
, startY
, and startScale
) which represent the x, y positions, and scale of the animated element. These values are essential for tracking and updating the element's position and scale during gestures.useAnimatedStyle
creates an animated style that updates based on the shared values. The style transforms the element by translating it along the x and y axes and scaling it according to offsetX
, offsetY
, and scale
.Gesture
API from react-native-gesture-handler
is used to handle pan and pinch gestures, allowing the element to be dragged and scaled.withSpring
function is used to animate the shared values with a spring effect, providing a smooth and natural animation when the gestures end.const offsetX = useSharedValue(0);
const offsetY = useSharedValue(0);
const scale = useSharedValue(1);
const startX = useSharedValue(0);
const startY = useSharedValue(0);
const startScale = useSharedValue(1);
These lines initialize the shared values to their default states.const animatedStyles = useAnimatedStyle(() => {
return {
transform: [
{ translateX: offsetX.value },
{ translateY: offsetY.value },
{ scale: scale.value },
],
};
});
This hook creates an animated style that updates the element's transform property based on the current values of offsetX
, offsetY
, and scale
.Gesture.Pan()
and Gesture.Pinch()
APIs to handle drag and scale gestures.const panGesture = Gesture.Pan()
.onStart(() => {
cancelAnimation(offsetX);
cancelAnimation(offsetY);
startX.value = offsetX.value;
startY.value = offsetY.value;
})
.onUpdate((event) => {
offsetX.value = startX.value + event.translationX;
offsetY.value = startY.value + event.translationY;
})
.onEnd(() => {
offsetX.value = withSpring(0);
offsetY.value = withSpring(0);
});
const pinchGesture = Gesture.Pinch()
.onStart(() => {
cancelAnimation(scale);
startScale.value = scale.value;
})
.onUpdate((event) => {
scale.value = startScale.value * event.scale;
})
.onEnd(() => {
scale.value = withSpring(1);
});
const composedGesture = Gesture.Simultaneous(panGesture, pinchGesture);
offsetX
and offsetY
values based on the gesture's translation.scale
value based on the gesture's scale.return (
<AnimationContainer title="Gesture Based Sequence" headingLight>
<FlexFull style={{ height: "100%", justifyContent: "center", alignItems: "center" }}>
<GestureDetector gesture={composedGesture}>
<Animated.View
style={[
elementStyleTwo,
animatedStyles,
{ width: 100, height: 100 },
]}
/>
</GestureDetector>
</FlexFull>
</AnimationContainer>
);
The component renders an animated view styled with both static and animated styles, representing an element that can be dragged and scaled.Animating text can enhance user experience by drawing attention or providing feedback. Reanimated offers various ways to animate text properties such as opacity, color, and scale.
useSharedValue
and useAnimatedStyle
for text animations.Example Six demonstrates the use of React Native Reanimated to create a sliding text animation. This component slides a text element from the left to the center of the screen using a timing animation. Here’s a detailed breakdown of its functionality and implementation.
useSharedValue
is used to create a shared value (translateX
) which represents the x position of the animated text element. This value is essential for tracking and updating the element's position during the animation.useAnimatedStyle
creates an animated style that updates based on the shared value. The style transforms the element by translating it along the x-axis according to translateX
.withTiming
function is used to animate the shared value with a timing effect, providing a smooth and controlled animation.useEffect
hook is used to trigger the animation when the component mounts.const translateX = useSharedValue(-350);
This line initializes the shared value translateX
to -350, starting the text element off-screen to the left.useEffect
hook triggers the animation when the component mounts.useEffect(() => {
translateX.value = withTiming(0, { duration: 2000 });
}, []);
const animatedStyles = useAnimatedStyle(() => ({
transform: [{ translateX: translateX.value }],
}));
This hook creates an animated style that updates the element's transform property based on the current value of translateX
.translateX
value.const restartAnimation = () => {
translateX.value = -350;
translateX.value = withTiming(0, { duration: 2000 });
};
return (
<AnimationContainer
height={screenHeight * 0.2}
title="Sliding Text"
resetAnimation={restartAnimation}
>
<FlexFull
style={{
height: "100%",
justifyContent: "center",
alignItems: "center",
}}
>
<Animated.Text
style={[
animatedStyles,
textShadows.glow200Sm,
{ fontFamily: "Play-Bold", fontSize: 33 },
]}
>
Slide to the right!
</Animated.Text>
</FlexFull>
</AnimationContainer>
);
The component renders an animated text element styled with both static and animated styles, representing text that slides in from the left.Example Seven demonstrates the use of React Native Reanimated to create a color-shifting text animation. This component changes the color of a text element in a looping sequence using timing and repeat animations. Here’s a detailed breakdown of its functionality and implementation.
useSharedValue
is used to create a shared value (color
) which represents the color transition state of the animated text element. This value is essential for tracking and updating the element's color during the animation.useAnimatedStyle
creates an animated style that updates based on the shared value. The style interpolates the color based on the value of color
.withTiming
function is used to animate the shared value with a timing effect, and withRepeat
is used to repeat the animation indefinitely.useEffect
hook is used to trigger the animation when the component mounts.interpolateColor
function is used to interpolate the color values based on the shared value.const color = useSharedValue(0);
This line initializes the shared value color
to 0.useEffect
hook triggers the color-shifting animation when the component mounts.useEffect(() => {
color.value = withRepeat(withTiming(1, { duration: 7000 }), -1, true);
}, []);
const animatedStyles = useAnimatedStyle(() => {
const textColor = interpolateColor(
color.value,
[0, 0.14, 0.28, 0.42, 0.56, 0.7, 0.84, 1],
[
col[200],
col[300],
col[400],
col[500],
col[600],
col[700],
col[800],
col[900],
]
);
return { color: textColor };
});
This hook creates an animated style that updates the element's color based on the interpolated value of color
.color
value.const restartAnimation = () => {
cancelAnimation(color);
color.value = 0;
color.value = withRepeat(withTiming(1, { duration: 7000 }), -1, true);
};
return (
<AnimationContainer
height={screenHeight * 0.2}
title="Color Shifting Text"
resetAnimation={restartAnimation}
>
<FlexFull
style={{
height: "100%",
justifyContent: "center",
alignItems: "center",
}}
>
<Animated.Text
style={[
animatedStyles,
textShadows.glow200Sm,
{ fontFamily: "Play-Bold", fontSize: 33 },
]}
>
Color shifting
</Animated.Text>
</FlexFull>
</AnimationContainer>
);
The component renders an animated text element styled with both static and animated styles, representing text that changes color in a looping sequence.Example Eight demonstrates the use of React Native Reanimated to create a rotating text animation. This component rotates a text element 360 degrees using a timing animation. Here’s a detailed breakdown of its functionality and implementation.
useSharedValue
is used to create a shared value (rotation
) which represents the rotation angle of the animated text element. This value is essential for tracking and updating the element's rotation during the animation.useAnimatedStyle
creates an animated style that updates based on the shared value. The style transforms the element by rotating it according to rotation
.withTiming
function is used to animate the shared value with a timing effect, providing a smooth and controlled animation.useEffect
hook is used to trigger the animation when the component mounts.const rotation = useSharedValue(0);
This line initializes the shared value rotation
to 0.useEffect
hook triggers the animation when the component mounts.useEffect(() => {
rotation.value = withTiming(360, { duration: 2000 });
}, []);
const animatedStyles = useAnimatedStyle(() => ({
transform: [{ rotate: `${rotation.value}deg` }],
}));
This hook creates an animated style that updates the element's transform property based on the current value of rotation
.rotation
value.const restartAnimation = () => {
rotation.value = 0;
rotation.value = withTiming(360, { duration: 2000 });
};
return (
<AnimationContainer
height={screenHeight * 0.3}
title="Rotating Text"
resetAnimation={restartAnimation}
>
<FlexFull
style={{
height: "100%",
justifyContent: "center",
alignItems: "center",
}}
>
<Animated.Text
style={[
animatedStyles,
textShadows.glow200Sm,
{ fontFamily: "Play-Bold", fontSize: 33 },
]}
>
Rotating Text
</Animated.Text>
</FlexFull>
</AnimationContainer>
);
The component renders an animated text element styled with both static and animated styles, representing text that rotates 360 degrees.Example Nine demonstrates the use of React Native Reanimated to create a skewed text animation. This component skews a text element along the x-axis using a timing animation. Here’s a detailed breakdown of its functionality and implementation.
useSharedValue
is used to create a shared value (skewX
) which represents the skew angle of the animated text element. This value is essential for tracking and updating the element's skew during the animation.useAnimatedStyle
creates an animated style that updates based on the shared value. The style transforms the element by skewing it along the x-axis according to skewX
.withTiming
function is used to animate the shared value with a timing effect, providing a smooth and controlled animation.useEffect
hook is used to trigger the animation when the component mounts.const skewX = useSharedValue(0);
This line initializes the shared value skewX
to 0.useEffect
hook triggers the animation when the component mounts.useEffect(() => {
skewX.value = withTiming(20, { duration: 2000 });
}, []);
const animatedStyles = useAnimatedStyle(() => ({
transform: [{ skewX: `${skewX.value}deg` }],
}));
This hook creates an animated style that updates the element's transform property based on the current value of skewX
.skewX
value.const restartAnimation = () => {
skewX.value = 0;
skewX.value = withTiming(20, { duration: 2000 });
};
return (
<AnimationContainer
height={screenHeight * 0.1}
title="Skewed Text"
resetAnimation={restartAnimation}
>
<FlexFull
style={{
height: "100%",
justifyContent: "center",
alignItems: "center",
}}
>
<Animated.Text
style={[
animatedStyles,
textShadows.glow200Sm,
{ fontFamily: "Play-Bold", fontSize: 33 },
]}
>
Skewed Text
</Animated.Text>
</FlexFull>
</AnimationContainer>
);
The component renders an animated text element styled with both static and animated styles, representing text that skews along the x-axis.Example Ten demonstrates the use of React Native Reanimated to create a sequenced skew animation. This component skews a text element back and forth in a sequence using timing animations. Here’s a detailed breakdown of its functionality and implementation.
useSharedValue
is used to create a shared value (skewX
) which represents the skew angle of the animated text element. This value is essential for tracking and updating the element's skew during the animation.useAnimatedStyle
creates an animated style that updates based on the shared value. The style transforms the element by skewing it along the x-axis according to skewX
.withTiming
function is used to animate the shared value with a timing effect, providing a smooth and controlled animation.withSequence
function is used to create a sequence of animations that play one after the other.useEffect
hook is used to trigger the animation when the component mounts.const skewX = useSharedValue(0);
This line initializes the shared value skewX
to 0.useEffect
hook triggers the animation sequence when the component mounts.useEffect(() => {
skewX.value = withSequence(
withTiming(20, { duration: 1000 }),
withTiming(-20, { duration: 1000 }),
withTiming(10, { duration: 1000 }),
withTiming(-10, { duration: 1000 }),
withTiming(0, { duration: 1000 })
);
}, []);
const animatedStyles = useAnimatedStyle(() => ({
transform: [{ skewX: `${skewX.value}deg` }],
}));
This hook creates an animated style that updates the element's transform property based on the current value of skewX
.skewX
value.const restartAnimation = () => {
skewX.value = 0;
skewX.value = withSequence(
withTiming(30, { duration: 1000 }),
withTiming(-30, { duration: 1000 }),
withTiming(20, { duration: 1000 }),
withTiming(-20, { duration: 1000 }),
withTiming(0, { duration: 1000 })
);
};
return (
<AnimationContainer
height={screenHeight * 0.1}
title="Sequenced Skewed Text"
resetAnimation={restartAnimation}
>
<FlexFull
style={{
height: "100%",
justifyContent: "center",
alignItems: "center",
}}
>
<Animated.Text
style={[
animatedStyles,
textShadows.glow200Sm,
{ fontFamily: "Play-Bold", fontSize: 33 },
]}
>
Skewed Text
</Animated.Text>
</FlexFull>
</AnimationContainer>
);
The component renders an animated text element styled with both static and animated styles, representing text that skews back and forth in a sequence.Example Eleven demonstrates the use of React Native Reanimated to create an animation that combines opacity and scale transformations. This component smoothly fades in and scales up a text element using timing animations. Here’s a detailed breakdown of its functionality and implementation.
useSharedValue
is used to create shared values (opacity
and scale
) which represent the opacity and scale of the animated text element. These values are essential for tracking and updating the element's opacity and scale during the animation.useAnimatedStyle
creates an animated style that updates based on the shared values. The style sets the element's opacity and transforms it by scaling according to opacity
and scale
.withTiming
function is used to animate the shared values with a timing effect, providing smooth and controlled animations.useEffect
hook is used to trigger the animation when the component mounts.const opacity = useSharedValue(0);
const scale = useSharedValue(0.5);
These lines initialize the shared values opacity
to 0 and scale
to 0.5.opacityScale
function defines the timing animations for opacity and scale.const opacityScale = () => {
opacity.value = withTiming(1, { duration: 2000 });
scale.value = withTiming(1, { duration: 2000 });
};
useEffect
hook triggers the animation when the component mounts.useEffect(() => {
opacityScale();
}, []);
const animatedStyles = useAnimatedStyle(() => ({
opacity: opacity.value,
transform: [{ scale: scale.value }],
}));
This hook creates an animated style that updates the element's opacity and transform properties based on the current values of opacity
and scale
.opacity
and scale
values.const restartAnimation = () => {
opacity.value = 0;
scale.value = 0.5;
opacityScale();
};
return (
<AnimationContainer
height={screenHeight * 0.1}
title="Opacity & Scale"
resetAnimation={restartAnimation}
>
<FlexFull
style={{
height: "100%",
justifyContent: "center",
alignItems: "center",
}}
>
<Animated.Text
style={[
animatedStyles,
textShadows.glow200Sm,
{ fontFamily: "Play-Bold", fontSize: 33 },
]}
>
Opacity & Scale
</Animated.Text>
</FlexFull>
</AnimationContainer>
);
The component renders an animated text element styled with both static and animated styles, representing text that smoothly fades in and scales up.Example Twelve demonstrates the use of React Native Reanimated to create a bouncing text animation. This component makes a text element bounce using a spring animation. Here’s a detailed breakdown of its functionality and implementation.
useSharedValue
is used to create a shared value (translateY
) which represents the y position of the animated text element. This value is essential for tracking and updating the element's position during the animation.useAnimatedStyle
creates an animated style that updates based on the shared value. The style transforms the element by translating it along the y-axis according to translateY
.withSpring
function is used to animate the shared value with a spring effect, providing a smooth and natural bouncing animation.useEffect
hook is used to trigger the animation when the component mounts.const translateY = useSharedValue(0);
This line initializes the shared value translateY
to 0.bouncingAnimation
function defines the spring animation for the y-axis translation.const bouncingAnimation = () => {
translateY.value = withSpring(-screenHeight * 0.13, {
damping: 5,
stiffness: 150,
});
};
useEffect
hook triggers the bouncing animation when the component mounts.useEffect(() => {
bouncingAnimation();
}, []);
const animatedStyles = useAnimatedStyle(() => ({
transform: [{ translateY: translateY.value }],
}));
translateY
value.const restartAnimation = () => {
translateY.value = 0;
bouncingAnimation();
};
return (
<AnimationContainer
height={screenHeight * 0.2}
title="Bouncing Text"
resetAnimation={restartAnimation}
>
<FlexFull
style={{
height: "100%",
justifyContent: "center",
alignItems: "flex-end",
}}
>
<Animated.Text
style={[
animatedStyles,
textShadows.glow200Sm,
{ fontFamily: "Play-Bold", fontSize: 33 },
]}
>
Bouncing Text
</Animated.Text>
</FlexFull>
</AnimationContainer>
);
The component renders an animated text element styled with both static and animated styles, representing text that bounces using a spring animation.Example Thirteen demonstrates the use of React Native Reanimated to create an animation that combines rotation and color transformation. This component rotates a text element while continuously changing its color using timing, repeat, and sequence animations. Here’s a detailed breakdown of its functionality and implementation.
useSharedValue
is used to create shared values (rotate
and color
) which represent the rotation angle and color transition state of the animated text element. These values are essential for tracking and updating the element's rotation and color during the animation.useAnimatedStyle
creates an animated style that updates based on the shared values. The style sets the element's rotation and color according to rotate
and color
.withTiming
function is used to animate the shared values with a timing effect, withRepeat
is used to repeat the animation, and withSequence
is used to create a sequence of animations that play one after the other.useEffect
hook is used to trigger the animation when the component mounts.interpolateColor
function is used to interpolate the color values based on the shared value.const rotate = useSharedValue(0);
const color = useSharedValue(0);
These lines initialize the shared values rotate
and color
to 0.rotatingColor
function defines the rotation and color animations using a combination of timing, repeat, and sequence animations.const rotatingColor = () => {
rotate.value = withRepeat(
withSequence(
withTiming(360, { duration: 2000 }),
withTiming(0, { duration: 0 })
),
-1,
false
);
color.value = withRepeat(withTiming(1, { duration: 5000 }), -1, true);
};
useEffect
hook triggers the animation when the component mounts.useEffect(() => {
rotatingColor();
}, []);
const animatedStyles = useAnimatedStyle(() => {
const textColor = interpolateColor(
color.value,
[0, 0.5, 1],
[col[300], col[400], col[500]]
);
return {
transform: [{ rotate: `${rotate.value}deg` }],
color: textColor,
};
});
rotate
and color
values.const restartAnimation = () => {
rotate.value = 0;
color.value = 0;
rotatingColor();
};
return (
<AnimationContainer
height={screenHeight * 0.3}
title="Rotating Color Text"
resetAnimation={restartAnimation}
>
<FlexFull
style={{
height: "100%",
justifyContent: "center",
alignItems: "center",
}}
>
<Animated.Text
style={[
animatedStyles,
textShadows.glow200Sm,
{ fontFamily: "Play-Bold", fontSize: 33 },
]}
>
Rotating Color
</Animated.Text>
</FlexFull>
</AnimationContainer>
);
Example Fourteen demonstrates the use of React Native Reanimated to create a pulsating text animation. This component scales a text element up and down continuously to create a pulsating effect using timing and repeat animations. Here’s a detailed breakdown of its functionality and implementation.
useSharedValue
is used to create a shared value (scale
) which represents the scale of the animated text element. This value is essential for tracking and updating the element's scale during the animation.useAnimatedStyle
creates an animated style that updates based on the shared value. The style transforms the element by scaling it according to scale
.withTiming
function is used to animate the shared value with a timing effect, and withRepeat
is used to repeat the animation indefinitely.useEffect
hook is used to trigger the animation when the component mounts.Easing.ease
function is used to create a smooth easing effect for the timing animation.const scale = useSharedValue(1);
This line initializes the shared value scale
to 1.pulsatingText
function defines the scaling animation using a combination of timing and repeat animations with easing.const pulsatingText = () => {
scale.value = withRepeat(
withTiming(1.4, { duration: 1000, easing: Easing.ease }),
-1,
true
);
};
useEffect
hook triggers the animation when the component mounts.useEffect(() => {
pulsatingText();
}, []);
const animatedStyles = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
}));
This hook creates an animated style that updates the element's transform property based on the current value of scale
.scale
value.const restartAnimation = () => {
scale.value = 1;
pulsatingText();
};
return (
<AnimationContainer
height={screenHeight * 0.1}
title="Pulsating Text"
resetAnimation={restartAnimation}
>
<FlexFull
style={{
height: "100%",
justifyContent: "center",
alignItems: "center",
}}
>
<Animated.Text
style={[
animatedStyles,
textShadows.glow200Sm,
{ fontFamily: "Play-Bold", fontSize: 33 },
]}
>
Pulsating Text
</Animated.Text>
</FlexFull>
</AnimationContainer>
);
The component renders an animated text element styled with both static and animated styles, representing text that scales up and down continuously to create a pulsating effect.Keyframe animations allow for more complex and predefined animation sequences. Reanimated’s keyframe API makes it easy to define animations that change multiple properties over time.
Example Fifteen demonstrates the use of React Native Reanimated to create an animation using keyframes. This component animates a text element using entering keyframes that control its opacity and translation along the y-axis. Here’s a detailed breakdown of its functionality and implementation.
useState
hook is used to manage the restart state and the entering keyframe. The restart state is used to re-trigger the keyframe animation, while the entering keyframe defines the animation sequence.Keyframe
API from React Native Reanimated is used to define the entering animation sequence. The keyframe controls the opacity and translation of the text element along the y-axis.useEffect
hook is used to reset the restart state after the animation is triggered.const [restart, setRestart] = useState(false);
const [enteringKeyframe, setEnteringKeyframe] = useState(
new Keyframe({
0: {
opacity: 0,
transform: [{ translateY: -50 }],
},
100: {
opacity: 1,
transform: [{ translateY: 0 }],
},
})
);
These lines initialize the state variables restart
and enteringKeyframe
. The keyframe animation is defined with an initial opacity of 0 and a translation of -50 units along the y-axis, and it transitions to an opacity of 1 and a translation of 0 units.restartAnimation
function redefines the entering keyframe and toggles the restart state to re-trigger the animation.const restartAnimation = () => {
setEnteringKeyframe(
new Keyframe({
0: {
opacity: 0,
transform: [{ translateY: -50 }],
},
100: {
opacity: 1,
transform: [{ translateY: 0 }],
},
})
);
setRestart((prev) => !prev);
};
useEffect
hook resets the restart state after the animation is triggered.useEffect(() => {
if (restart) {
setRestart(false);
}
}, [restart]);
return (
<AnimationContainer
height={screenHeight * 0.1}
title="Entering Keyframes"
resetAnimation={restartAnimation}
headingLight
>
<FlexFull
style={{
height: "100%",
justifyContent: "center",
alignItems: "center",
}}
>
<Animated.View
key={restart.toString()}
entering={enteringKeyframe}
style={[elementStyleTwo, { paddingHorizontal: 10 }]}
>
<TextLg>Entering Keyframes</TextLg>
</Animated.View>
</FlexFull>
</AnimationContainer>
);
The component renders an animated view styled with both static and animated styles, representing text that animates using entering keyframes.Example Sixteen demonstrates the use of React Native Reanimated to create an animation using sequential keyframes. This component animates a text element through a sequence of keyframes that control its opacity, translation, scaling, and rotation. Here’s a detailed breakdown of its functionality and implementation.
useState
hook is used to manage the restart state and the entering keyframe. The restart state is used to re-trigger the keyframe animation, while the entering keyframe defines the animation sequence.Keyframe
API from React Native Reanimated is used to define the sequential animation sequence. The keyframe controls the opacity, translation, scaling, and rotation of the text element.useEffect
hook is used to reset the restart state after the animation is triggered.const [restart, setRestart] = useState(false);
const keyframeAnimation = new Keyframe({
0: {
opacity: 0,
transform: [{ translateY: -50 }, { scale: 0.5 }, { rotate: "0deg" }],
},
25: {
opacity: 0.5,
transform: [{ translateY: -50 }, { scale: 0.75 }, { rotate: "90deg" }],
},
50: {
opacity: 0.75,
transform: [{ translateY: 0 }, { scale: 1 }, { rotate: "180deg" }],
},
75: {
opacity: 1,
transform: [{ translateY: 50 }, { scale: 1.25 }, { rotate: "270deg" }],
},
100: {
opacity: 1,
transform: [{ translateY: 0 }, { scale: 1 }, { rotate: "360deg" }],
},
}).duration(500);
const [enteringKeyframe, setEnteringKeyframe] = useState(keyframeAnimation);
These lines initialize the state variables restart
and enteringKeyframe
. The keyframe animation is defined with sequential steps controlling opacity, translation, scaling, and rotation.restartAnimation
function redefines the entering keyframe and toggles the restart state to re-trigger the animation.const restartAnimation = () => {
setEnteringKeyframe(keyframeAnimation);
setRestart((prev) => !prev);
};
useEffect
hook resets the restart state after the animation is triggered.useEffect(() => {
if (restart) {
setRestart(false);
}
}, [restart]);
return (
<AnimationContainer
height={screenHeight * 0.3}
title="Sequential Keyframes"
resetAnimation={restartAnimation}
headingLight
>
<FlexFull
style={{
height: "100%",
justifyContent: "center",
alignItems: "center",
}}
>
<Animated.View
key={restart.toString()}
entering={enteringKeyframe}
style={[elementStyleTwo, { paddingHorizontal: 10 }]}
>
<TextLg>Sequential Keyframes</TextLg>
</Animated.View>
</FlexFull>
</AnimationContainer>
);
The component renders an animated view styled with both static and animated styles, representing text that animates through a sequence of keyframes.Example Seventeen demonstrates the use of React Native Reanimated to create an advanced animation sequence using keyframes. This component animates a text element through a series of keyframes that control its opacity, translation, scaling, rotation, and background color. Here’s a detailed breakdown of its functionality and implementation.
useState
hook is used to manage the restart state. The restart state is used to re-trigger the keyframe animation.Keyframe
API from React Native Reanimated is used to define the advanced animation sequence. The keyframe controls the opacity, translation, scaling, rotation, and background color of the text element.useEffect
hook is used to reset the restart state after the animation is triggered.const [restart, setRestart] = useState(false);
const keyframeAnimation = new Keyframe({
0: {
opacity: 0,
transform: [{ translateY: -100 }, { scale: 0.5 }, { rotate: "0deg" }],
backgroundColor: col[300],
},
20: {
opacity: 0.5,
transform: [{ translateY: -50 }, { scale: 0.75 }, { rotate: "90deg" }],
backgroundColor: col[400],
},
40: {
opacity: 1,
transform: [{ translateY: 0 }, { scale: 1 }, { rotate: "180deg" }],
backgroundColor: col[500],
},
60: {
opacity: 0.75,
transform: [{ translateY: 50 }, { scale: 1.25 }, { rotate: "270deg" }],
backgroundColor: col[600],
},
80: {
opacity: 0.5,
transform: [{ translateY: 100 }, { scale: 1.5 }, { rotate: "360deg" }],
backgroundColor: col[500],
},
100: {
opacity: 1,
transform: [{ translateY: 0 }, { scale: 1 }, { rotate: "0deg" }],
backgroundColor: col[400],
},
}).duration(2000);
These lines initialize the state variable restart
and define the keyframe animation with advanced sequential steps controlling opacity, translation, scaling, rotation, and background color.restartAnimation
function toggles the restart state to re-trigger the animation.const restartAnimation = () => {
setRestart((prev) => !prev);
};
useEffect
hook resets the restart state after the animation is triggered.useEffect(() => {
if (restart) {
setRestart(false);
}
}, [restart]);
return (
<AnimationContainer
height={screenHeight * 0.3}
title="Advanced Sequence"
resetAnimation={restartAnimation}
headingLight
>
<FlexFull
style={{
height: "100%",
justifyContent: "center",
alignItems: "center",
}}
>
<Animated.View
key={restart.toString()}
entering={keyframeAnimation}
style={[
boxShadows.xl,
{
borderRadius: 20,
justifyContent: "center",
alignItems: "center",
},
]}
>
<View
style={{
paddingHorizontal: 10,
justifyContent: "center",
alignItems: "center",
}}
>
<TextLg>Advanced Sequence</TextLg>
</View>
</Animated.View>
</FlexFull>
</AnimationContainer>
);
The component renders an animated view styled with both static and animated styles, representing text that animates through an advanced sequence of keyframes.Animating based on scroll position can create engaging and intuitive UIs. Reanimated provides tools to trigger animations based on the scroll position.
Our final example demonstrates the use of React Native Reanimated to create a scrollable list that can be programmatically scrolled to specific items. This component utilizes animated references and shared values to control the scroll position of an Animated.ScrollView
. Here’s a detailed breakdown of its functionality and implementation.
useAnimatedRef
is used to create a reference to the Animated.ScrollView
. This reference is essential for controlling the scroll position programmatically.useSharedValue
is used to create a shared value (scroll
) which represents the current scroll position. This value is essential for tracking and updating the scroll position during the animation.useDerivedValue
is used to derive the scroll position from the shared value and trigger the scrollTo function to update the scroll position of the Animated.ScrollView
.scrollTo
function is used to programmatically scroll to a specific position in the Animated.ScrollView
based on the shared value.const animatedRef = useAnimatedRef<Animated.ScrollView>();
const scroll = useSharedValue<number>(0);
These lines initialize the animated reference animatedRef
and the shared value scroll
.useDerivedValue
hook derives the scroll position from the shared value and triggers the scrollTo
function to update the scroll position.useDerivedValue(() => {
scrollTo(
animatedRef,
0,
scroll.value * SCROLL_CONTAINER_HEIGHT - 100,
true
);
});
const items = Array.from(Array(100).keys());
return (
<GradientTen style={{ paddingTop: 70 }}>
<VStackFull style={{ height: screenHeight * 0.9, gap: 10 }}>
<NavButton increment={-1} scroll={scroll} />
<CenterHorizontalFull style={{ height: SCROLL_CONTAINER_HEIGHT }}>
<Animated.ScrollView ref={animatedRef}>
<VStackFull style={{ gap: 25, paddingVertical: 10 }}>
{items.map((_, i) => (
<CenterHorizontalFull key={i}>
<View
style={[
elementStyleTwo,
{
height: 70,
width: screenWidth * 0.75,
justifyContent: "center",
alignItems: "center",
},
]}
>
<TextXl style={{ textAlign: "center" }}>Item: {i}</TextXl>
</View>
</CenterHorizontalFull>
))}
</VStackFull>
</Animated.ScrollView>
</CenterHorizontalFull>
<NavButton increment={1} scroll={scroll} />
</VStackFull>
</GradientTen>
);
The component renders a gradient background with a scrollable list of items. Navigation buttons are provided to scroll up and down through the list.const NavButton = ({
increment,
scroll,
}: {
increment: number;
scroll: SharedValue<number>;
}) => (
<CenterHorizontalFull>
<MyButton
icon={
increment > 0 ? "caret-down-circle-outline" : "caret-up-circle-outline"
}
onPress={() => {
scroll.value =
scroll.value + increment > 0
? scroll.value + increment
: 100 - 1 + increment;
if (scroll.value >= 100 - 2) scroll.value = 0;
}}
text={`Page ${increment > 0 ? "down" : "up"}`}
/>
</CenterHorizontalFull>
);
We've delved deeply into the capabilities and nuances of React Native Reanimated, showcasing a variety of animation techniques and their practical applications. From simple movements along the X and Y axes to sophisticated gesture-based interactions and advanced keyframe sequences, we've explored how React Native Reanimated can transform the user experience with smooth, interactive animations.
useSharedValue
) and animated styles (useAnimatedStyle
) form the backbone of reanimated components, enabling dynamic and responsive animations.withTiming
and withSpring
, we've created animations that smoothly transition between states or simulate natural physical behaviors like bouncing.react-native-gesture-handler
, we've crafted interactive components that respond to user gestures, enhancing the interactivity of our apps.scrollTo
and animated references, we've learned how to create scrollable lists that can be programmatically controlled, offering a more guided and interactive scrolling experience.Through these examples, you should now have a solid foundation to start implementing your own animations in React Native. The versatility of Reanimated opens up numerous possibilities for creating engaging, dynamic user interfaces. Whether you are building a simple app or a complex interactive experience, understanding and utilizing the techniques covered in this post will help you deliver a more polished and professional product.
Animation is a critical aspect of modern mobile app development, enhancing the user experience by making interactions more intuitive and visually appealing. React Native Reanimated stands out as a powerful library that not only makes it easier to implement these animations but also offers the performance and control needed to create sophisticated, fluid animations. By integrating these techniques into your projects, you can elevate the user experience and create applications that truly stand out.
Thank you for following along with this exploration of React Native Reanimated. I hope these insights and examples inspire you to experiment and create your own stunning animations. Keep pushing the boundaries of what’s possible, and happy animating!