Stack navigator component for iOS and Android with animated transitions and gestures
—
Utility hooks and context providers for accessing animation values and gesture handlers within screen components, enabling custom animations and gesture-aware components.
Hook that provides access to card animation interpolation properties within stack screen components.
/**
* Hook to access card animation values within stack screens
* @returns Card animation interpolation properties
* @throws Error if called outside of a stack screen context
*/
function useCardAnimation(): StackCardInterpolationProps;Usage Examples:
import React from 'react';
import { Animated, View } from 'react-native';
import { useCardAnimation } from '@react-navigation/stack';
function AnimatedScreen() {
const { current, closing, swiping } = useCardAnimation();
// Create custom animations based on card animation progress
const customOpacity = current.progress.interpolate({
inputRange: [0, 1],
outputRange: [0.3, 1],
});
const customScale = current.progress.interpolate({
inputRange: [0, 1],
outputRange: [0.9, 1],
});
const customRotation = current.progress.interpolate({
inputRange: [0, 1],
outputRange: ['-5deg', '0deg'],
});
return (
<Animated.View
style={{
flex: 1,
opacity: customOpacity,
transform: [
{ scale: customScale },
{ rotate: customRotation },
],
}}
>
<View style={{ padding: 20 }}>
<Text>Custom Animated Content</Text>
{/* Animate based on swipe gesture */}
<Animated.View
style={{
opacity: swiping.interpolate({
inputRange: [0, 1],
outputRange: [1, 0.5],
}),
}}
>
<Text>This fades during swipe gestures</Text>
</Animated.View>
{/* Animate based on closing state */}
<Animated.View
style={{
transform: [{
translateY: closing.interpolate({
inputRange: [0, 1],
outputRange: [0, -20],
}),
}],
}}
>
<Text>This moves up when closing</Text>
</Animated.View>
</View>
</Animated.View>
);
}Hook that provides access to the gesture handler reference for coordinating custom gestures with navigation gestures.
/**
* Hook to access gesture handler ref within stack screens
* @returns Gesture handler reference for coordination with navigation gestures
* @throws Error if called outside of a stack screen context
*/
function useGestureHandlerRef(): React.Ref<PanGestureHandler>;Usage Examples:
import React from 'react';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
import { useGestureHandlerRef } from '@react-navigation/stack';
function GestureAwareScreen() {
const navigationGestureRef = useGestureHandlerRef();
const customGestureRef = useRef();
const handleGestureEvent = (event) => {
// Custom gesture handling that works with navigation gestures
console.log('Custom gesture:', event.nativeEvent);
};
const handleStateChange = (event) => {
if (event.nativeEvent.state === State.END) {
console.log('Custom gesture ended');
}
};
return (
<PanGestureHandler
ref={customGestureRef}
onGestureEvent={handleGestureEvent}
onHandlerStateChange={handleStateChange}
simultaneousHandlers={navigationGestureRef} // Allow simultaneous gestures
>
<View style={{ flex: 1 }}>
<Text>Swipe me while navigation gestures still work!</Text>
</View>
</PanGestureHandler>
);
}React context that provides card animation interpolation properties to child components.
/**
* Context providing card animation interpolation props to child components
* Value is undefined when not within a stack screen
*/
const CardAnimationContext: React.Context<StackCardInterpolationProps | undefined>;Usage Examples:
import React, { useContext } from 'react';
import { CardAnimationContext } from '@react-navigation/stack';
function CustomAnimatedComponent() {
const animationProps = useContext(CardAnimationContext);
if (!animationProps) {
// Not within a stack screen, render without animation
return <StaticComponent />;
}
const { current, next, closing } = animationProps;
const animatedOpacity = current.progress.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
});
return (
<Animated.View style={{ opacity: animatedOpacity }}>
<Text>Animated based on card transition</Text>
</Animated.View>
);
}
// Provider usage (automatically provided by stack navigator)
function CustomScreen() {
return (
<View>
<CustomAnimatedComponent />
</View>
);
}React context that provides the gesture handler reference for coordinating custom gestures.
/**
* Context providing gesture handler ref to child components
* Value is null when not within a stack screen
*/
const GestureHandlerRefContext: React.Context<React.Ref<PanGestureHandler> | null>;Usage Examples:
import React, { useContext } from 'react';
import { PanGestureHandler } from 'react-native-gesture-handler';
import { GestureHandlerRefContext } from '@react-navigation/stack';
function NestedGestureComponent() {
const navigationGestureRef = useContext(GestureHandlerRefContext);
return (
<PanGestureHandler
simultaneousHandlers={navigationGestureRef}
onGestureEvent={(event) => {
// Handle custom gesture while preserving navigation gestures
console.log('Nested gesture:', event.nativeEvent);
}}
>
<View style={{ padding: 20, backgroundColor: 'lightblue' }}>
<Text>This area has custom gestures that work with navigation</Text>
</View>
</PanGestureHandler>
);
}Combine multiple animation utilities for complex effects:
import { useCardAnimation, useGestureHandlerRef } from '@react-navigation/stack';
function AdvancedAnimatedScreen() {
const { current, next, closing, swiping } = useCardAnimation();
const gestureRef = useGestureHandlerRef();
// Parallax effect with background
const backgroundTranslateX = current.progress.interpolate({
inputRange: [0, 1],
outputRange: [100, 0],
});
// Content animation with gesture awareness
const contentOpacity = Animated.multiply(
current.progress,
swiping.interpolate({
inputRange: [0, 1],
outputRange: [1, 0.7],
})
);
return (
<View style={{ flex: 1 }}>
{/* Animated background */}
<Animated.View
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'lightblue',
transform: [{ translateX: backgroundTranslateX }],
}}
/>
{/* Animated content */}
<Animated.View
style={{
flex: 1,
opacity: contentOpacity,
}}
>
<Text>Advanced coordinated animation</Text>
</Animated.View>
</View>
);
}Use animation context for conditional rendering and animations:
function ConditionalAnimationScreen() {
const animationProps = useCardAnimation();
const isAnimating = animationProps ? animationProps.current.progress._value < 1 : false;
return (
<View style={{ flex: 1 }}>
{isAnimating ? (
<LoadingComponent />
) : (
<MainContent />
)}
{animationProps && (
<Animated.View
style={{
position: 'absolute',
bottom: 20,
right: 20,
opacity: animationProps.current.progress.interpolate({
inputRange: [0.8, 1],
outputRange: [0, 1],
extrapolate: 'clamp',
}),
}}
>
<FloatingActionButton />
</Animated.View>
)}
</View>
);
}Complete properties available through animation utilities:
interface StackCardInterpolationProps {
current: {
progress: Animated.AnimatedInterpolation<number>;
};
next?: {
progress: Animated.AnimatedInterpolation<number>;
};
index: number;
closing: Animated.AnimatedInterpolation<0 | 1>;
swiping: Animated.AnimatedInterpolation<0 | 1>;
inverted: Animated.AnimatedInterpolation<-1 | 1>;
layouts: {
screen: Layout;
};
insets: {
top: number;
right: number;
bottom: number;
left: number;
};
}
interface Layout {
width: number;
height: number;
}These properties enable:
Install with Tessl CLI
npx tessl i tessl/npm-react-navigation--stack