Skip to main content
Version: 3.x

Quick start

RNGH3 offers a straightforward way to add gestures to your app. Simply wrap your target view with the GestureDetector component, define your gesture, and pass it in. That’s it!

To see the new API in action, let's build a simple app where you can drag a ball around the screen. To follow along, you'll need both react-native-gesture-handler (to handle gestures) and react-native-reanimated (to handle the animations).

Step 1
Start by defining the basic structure of the application:
import { StyleSheet } from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import Animated from 'react-native-reanimated';

export default function Ball() {
return (
<GestureHandlerRootView>
<Animated.View style={styles.ball} />
</GestureHandlerRootView>
);
}

const styles = StyleSheet.create({
ball: {
width: 100,
height: 100,
borderRadius: 100,
backgroundColor: 'blue',
alignSelf: 'center',
},
});
Step 2

Next, define the SharedValues to track the ball's position and create the animated styles required to position the ball on the screen:

import {
useAnimatedStyle,
useSharedValue,
withSpring,
} from 'react-native-reanimated';

export default function Ball() {
const isPressed = useSharedValue(false);
const offset = useSharedValue({ x: 0, y: 0 });

const animatedStyles = useAnimatedStyle(() => {
return {
transform: [
{ translateX: offset.value.x },
{ translateY: offset.value.y },
{ scale: withSpring(isPressed.value ? 1.2 : 1) },
],
backgroundColor: isPressed.value ? 'yellow' : 'blue',
};
});

// ...
}
Step 3
Apply the animated styles to the ball component:
// ...
return (
<GestureHandlerRootView>
<Animated.View style={[styles.ball, animatedStyles]} />
</GestureHandlerRootView>
);
// ...
Step 4

Now, define the Pan gesture logic.

import { usePanGesture } from 'react-native-gesture-handler';

function Ball() {
// ...
const gesture = usePanGesture({
onBegin: () => {
isPressed.value = true;
},
onUpdate: (e) => {
offset.value = {
x: offset.value.x + e.changeX,
y: offset.value.y + e.changeY,
};
},
onFinalize: () => {
isPressed.value = false;
},
});
// ...
}
Step 5

Finally, wrap the component responsible for rendering the ball with a GestureDetector, and attach the Pan gesture to it:

// ...
return (
<GestureHandlerRootView>
<GestureDetector gesture={gesture}>
<Animated.View style={[styles.ball, animatedStyles]} />
</GestureDetector>
</GestureHandlerRootView>
);
// ...

The complete implementation is shown below:

import { StyleSheet } from 'react-native';
import {
GestureDetector,
GestureHandlerRootView,
usePanGesture,
} from 'react-native-gesture-handler';
import Animated, {
useAnimatedStyle,
useSharedValue,
withSpring,
} from 'react-native-reanimated';

export default function Ball() {
const isPressed = useSharedValue(false);
const offset = useSharedValue({ x: 0, y: 0 });

const gesture = usePanGesture({
onBegin: () => {
isPressed.value = true;
},
onUpdate: (e) => {
offset.value = {
x: offset.value.x + e.changeX,
y: offset.value.y + e.changeY,
};
},
onFinalize: () => {
isPressed.value = false;
},
});

const animatedStyles = useAnimatedStyle(() => {
return {
transform: [
{ translateX: offset.value.x },
{ translateY: offset.value.y },
{ scale: withSpring(isPressed.value ? 1.2 : 1) },
],
backgroundColor: isPressed.value ? 'yellow' : 'blue',
};
});

return (
<GestureHandlerRootView>
<GestureDetector gesture={gesture}>
<Animated.View style={[styles.ball, animatedStyles]} />
</GestureDetector>
</GestureHandlerRootView>
);
}

const styles = StyleSheet.create({
ball: {
width: 100,
height: 100,
borderRadius: 100,
backgroundColor: 'blue',
alignSelf: 'center',
},
});