Using React Native Gesture Handler
1. Installing Gesture Handler
React Native Gesture Handler is a library that provides native gesture recognition for React Native applications. It allows you to handle complex gestures like pan, pinch, and rotation with high performance.
| Step | Description | Command |
|---|---|---|
| 1 | Install the Gesture Handler library using npm or yarn | npm install react-native-gesture-handler |
| 2 | For iOS, run pod install to link native dependencies | npx pod-install |
Note: Make sure to follow the setup instructions for both iOS and Android platforms as outlined in the official documentation.
Example: Basic Setup
import 'react-native-gesture-handler'; // Must be imported at the top of your app entry point
// Example usage in a component
import { PanGestureHandler } from 'react-native-gesture-handler';
<PanGestureHandler>
<View style={styles.box} />
</PanGestureHandler>
2. Using Tap Gesture Handler
| Property | Description | Default | Notes |
|---|---|---|---|
| numberOfTaps | Number of taps required to trigger the handler | 1 |
Can be 1 or 2 for double tap |
| maxDurationMs | Maximum duration in milliseconds to consider a tap | 500 |
Used to detect quick taps |
| minPointers | Minimum number of pointers (fingers) required to trigger the handler | 1 |
Can be 1 or more for multi-touch support |
| maxDist | Maximum distance in pixels that the pointer can move to still be considered a tap | 50 |
Prevents movement from being interpreted as a tap |
Example: Basic Tap Gesture Handler
import { TapGestureHandler } from 'react-native-gesture-handler';
<TapGestureHandler
numberOfTaps={1}
maxDurationMs={500}
maxDist={50}
>
<View style={styles.button}>
<Text>Tap Me</Text>
</View>
</TapGestureHandler>
Example: Double Tap Gesture Handler
import { TapGestureHandler } from 'react-native-gesture-handler';
<TapGestureHandler
numberOfTaps={2}
maxDurationMs={300}
>
<View style={styles.doubleTapArea}>
<Text>Double Tap</Text>
</View>
</TapGestureHandler>
Note: The
maxDist property is useful for ensuring that a user's slight movement (e.g., shaking the finger) doesn't count as a tap.
3. Using Pan Gesture Handler
| Property | Description | Default | Notes |
|---|---|---|---|
| onGestureEvent | Callback function for gesture events | null |
Used to handle pan movement and update state |
| onHandlerStateChange | Callback for handler state changes (BEGIN, END, etc.) | null |
Useful for detecting when gesture starts or ends |
| activeOffsetX | Active offset for X axis (in pixels) | 0 |
Minimum movement before gesture is considered active |
| activeOffsetY | Active offset for Y axis (in pixels) | 0 |
Minimum movement before gesture is considered active |
| failOffsetX | Fail offset for X axis (in pixels) | 0 |
If movement exceeds this, gesture fails |
| failOffsetY | Fail offset for Y axis (in pixels) | 0 |
If movement exceeds this, gesture fails |
Example: Basic Pan Gesture Handler
import React, { useRef } from 'react';
import { View } from 'react-native';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
const PanExample = () => {
const translationX = useRef(new Animated.Value(0)).current;
const translationY = useRef(new Animated.Value(0)).current;
const onGestureEvent = Animated.event([
{ nativeEvent: { translationX: translationX } },
{ nativeEvent: { translationY: translationY } }
], { useNativeDriver: true });
const onHandlerStateChange = (event) => {
if (event.nativeEvent.state === State.END) {
translationX.setValue(0);
translationY.setValue(0);
}
};
return (
<PanGestureHandler
onGestureEvent={onGestureEvent}
onHandlerStateChange={onHandlerStateChange}
>
<Animated.View
style={[
styles.box,
{
transform: [
{ translateX: translationX },
{ translateY: translationY }
]
}
]}
>
</Animated.View>
</PanGestureHandler>
);
};
const styles = StyleSheet.create({
box: {
width: 100,
height: 100,
backgroundColor: 'blue',
borderRadius: 10
}
});
Note: The
Animated.event is used to map gesture properties to animated values. Ensure that useNativeDriver is set to true for better performance.
Warning: Make sure to properly handle the
State.END event to reset the animated values if needed, otherwise the component might not behave as expected.
4. Using Pinch Gesture Handler
| Property | Description | Default | Notes |
|---|---|---|---|
| enabled | Enables or disables the pinch gesture handler | true |
Set to false to disable the gesture |
| minScale | Minimum scale factor allowed for the pinch gesture | 0.5 |
Value must be greater than 0 |
| maxScale | Maximum scale factor allowed for the pinch gesture | 3.0 |
Value must be greater than minScale |
| onGestureEvent | Callback function for gesture events | null |
Used to update animated values during the gesture |
| onHandlerStateChange | Callback function for handler state changes | null |
Used to handle gesture start and end events |
Example: Basic Pinch Gesture Handler
import { PinchGestureHandler, State } from 'react-native-gesture-handler';
import Animated, { useAnimatedRef, useAnimatedStyle } from 'react-native-reanimated';
const PinchExample = () => {
const scale = useSharedValue(1);
const animatedRef = useAnimatedRef();
const onGestureEvent = event => {
scale.value = event.nativeEvent.scale;
};
const onHandlerStateChange = event => {
if (event.nativeEvent.oldState === State.BEGAN) {
scale.value = 1;
}
};
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [{ scale: scale.value }],
};
});
return (
<PinchGestureHandler
onGestureEvent={onGestureEvent}
onHandlerStateChange={onHandlerStateChange}>
<Animated.View style={[animatedStyle, { width: 200, height: 200 }]}>
<View style={{ backgroundColor: 'blue', width: '100%', height: '100%' }} />
</Animated.View>
</PinchGestureHandler>
);
};
Note: The
PinchGestureHandler requires a child component that is an Animated.View or similar animated component to apply transformations.
Warning: Ensure that the
scale value is clamped between minScale and maxScale to prevent unexpected behavior.
5. Using Rotation Gesture Handler
| Property | Description | Default | Notes |
|---|---|---|---|
| rotation | Rotation angle in radians | 0 |
Read-only value, updated by gesture |
| onGestureEvent | Callback for gesture updates | null |
Used to update animated values |
| onEnd | Callback when gesture ends | null |
Triggers after rotation completes |
Example: Rotation Gesture Handler
import { RotationGestureHandler, State } from 'react-native-gesture-handler';
import Animated, { useAnimatedStyle, useSharedValue } from 'react-native-reanimated';
const rotation = useSharedValue(0);
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [{ rotate: rotation.value + 'rad' }]
};
});
const onGestureEvent = (event) => {
rotation.value = event.nativeEvent.rotation;
};
const onHandlerStateChange = (event) => {
if (event.nativeEvent.state === State.END) {
rotation.value = 0;
}
};
<RotationGestureHandler
onGestureEvent={onGestureEvent}
onHandlerStateChange={onHandlerStateChange}>
<Animated.View style={animatedStyle}>
<View style={{ width: 100, height: 100, backgroundColor: 'blue' }} />
</Animated.View>
</RotationGestureHandler>
Note: The
rotation value is in radians. For degrees, multiply by 180 / Math.PI.
Warning: Ensure that the
rotation value is reset on gesture end to prevent accumulation.
6. Combining Multiple Gestures
React Native Gesture Handler allows combining multiple gestures into complex touch interactions. This is achieved using gesture composition methods like gesture1.andThen(gesture2), gesture1.orElse(gesture2), and gesture1.exclusive(gesture2).
| Gestures | Composition Method | Description |
|---|---|---|
| PanGesture | andThen() |
Executes gesture2 only after gesture1 completes successfully. |
| TapGesture | orElse() |
Triggers gesture2 if gesture1 fails to recognize. |
| LongPressGesture | exclusive() |
Prevents gesture2 from starting if gesture1 is active. |
Example: Combining Pan and Tap Gestures
import { PanGestureHandler, TapGestureHandler } from 'react-native-gesture-handler';\n\nconst panGesture = PanGestureHandler.create({\n minDist: 10,\n maxPointers: 1\n});\n\nconst tapGesture = TapGestureHandler.create({\n maxDuration: 200,\n minPointers: 1\n});\n\nconst combinedGesture = panGesture.andThen(tapGesture);\n\n// Usage in component\n<PanGestureHandler gesture={combinedGesture}>\n <View>...</View>\n</PanGestureHandler>
Example: Exclusive Long Press and Pan
import { LongPressGestureHandler, PanGestureHandler } from 'react-native-gesture-handler';\n\nconst longPress = LongPressGestureHandler.create({\n minDuration: 500\n});\n\nconst pan = PanGestureHandler.create({\n minDist: 10\n});\n\nconst exclusiveGesture = longPress.exclusive(pan);\n\n// Usage in component\n<LongPressGestureHandler gesture={exclusiveGesture}>\n <View>...</View>\n</LongPressGestureHandler>
7. Handling Gesture State
| State | Description | Values |
|---|---|---|
| BEGAN | Gesture has started | BEGAN |
| FAILED | Gesture has failed to recognize | FAILED |
| ACTIVE | Gesture is active and recognized | ACTIVE |
| END | Gesture has ended | END |
| CANCELLED | Gesture was cancelled | CANCELLED |
Example: Using State in Gesture Handler
import { State } from 'react-native-gesture-handler';
const handleGestureStateChange = (event) => {
const { state } = event.nativeEvent;
switch (state) {
case State.BEGAN:
console.log('Gesture started');
break;
case State.ACTIVE:
console.log('Gesture active');
break;
case State.END:
console.log('Gesture ended');
break;
case State.CANCELLED:
console.log('Gesture cancelled');
break;
}
};
8. Using Fling Gesture Handler
| Property | Description | Default | Notes |
|---|---|---|---|
| fling | Enables fling gesture recognition | false |
Set to true to enable fling gestures |
| direction | Direction of the fling gesture | Directions.RIGHT |
One of RIGHT, LEFT, UP, or DOWN |
| threshold | Minimum velocity threshold to recognize a fling | 0.5 |
Velocity in pixels per second |
| vibration | Whether to vibrate on gesture recognition | false |
Set to true to enable vibration feedback |
Example: Fling Gesture Handler Setup
import { Fling } from 'react-native-gesture-handler';
<Fling
direction={Fling.Directions.RIGHT}
threshold={0.5}
onGestureEvent={(event) => {
console.log('Fling detected:', event.nativeEvent);
}}
>
<View style={styles.box}></View>
</Fling>
Note: The
Fling gesture handler is ideal for swipe-based navigation or list interactions where a quick directional swipe should trigger an action.
9. Implementing Gesture Callbacks
| Callback | Description | Parameters | Notes |
|---|---|---|---|
| onStart | Called when the gesture starts | gestureState |
Initial state of the gesture |
| onActive | Called when the gesture becomes active | gestureState |
Updated state during gesture |
| onEnd | Called when the gesture ends | gestureState |
Final state of the gesture |
| onFail | Called when the gesture fails to activate | gestureState |
Gesture did not meet activation criteria |
| onCancel | Called when the gesture is cancelled | gestureState |
Gesture was interrupted |
Example: Handling Gesture Callbacks
import { Gesture } from 'react-native-gesture-handler';
const gesture = Gesture.Tap()
.onStart((event) => {
console.log('Gesture started');
})
.onActive((event) => {
console.log('Gesture active');
})
.onEnd((event) => {
console.log('Gesture ended');
});
10. Integrating with Reanimated
React Native Gesture Handler and Reanimated can be used together to create complex, performant animations that respond to user gestures. This integration allows for smooth, native-like interactions.
| Feature | Description | Usage |
|---|---|---|
| PanGestureHandler | Handles pan gestures for drag interactions. | const pan = Gesture.Pan().onUpdate((e) => { ... }); |
| Reanimated | Used for declarative animations and gesture-based state updates. | useAnimatedStyle(() => { ... }) |
Example: Pan Gesture with Reanimated
import { PanGestureHandler } from 'react-native-gesture-handler';
import Animated, { useAnimatedStyle, useSharedValue } from 'react-native-reanimated';
const translateX = useSharedValue(0);
const translateY = useSharedValue(0);
const pan = Gesture.Pan()
.onUpdate((e) => {
translateX.value = e.translationX;
translateY.value = e.translationY;
})
.onEnd(() => {
translateX.value = 0;
translateY.value = 0;
});
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [
{ translateX: translateX.value },
{ translateY: translateY.value }
]
};
});
<PanGestureHandler gesture={pan}>
<Animated.View style={animatedStyle}>
<View style={{ width: 100, height: 100, backgroundColor: 'blue' }} />
</Animated.View>
</PanGestureHandler>
Note: Ensure that
react-native-gesture-handler and react-native-reanimated are properly linked and configured in your project.
Warning: Reanimated requires specific setup in
babel.config.js and index.js to function correctly.