Taps, swipes, pinches, and rotations are part of the gestures that are used to create a seamless user experience in mobile applications. React Native provides built-in gesture handling through components such as TouchableOpacity, ScrollView, and others. However, the built-in solutions may not cover more complex gesture interactions or provide the flexibility needed for highly customized behaviors.
This is where react-native-gesture-handler comes into play, offering a comprehensive set of tools for advanced gesture handling.
However, it has several benefits over the system used by default in React Native:
react-native-gesture-handler offers a declarative API that fits well with the component-based architecture of React.
Before delving into gesture handling, let's add the library react-native-gesture-handler to your React Native project:
Installation
First, install the library using npm or yarn:
# Using npm
npm install react-native-gesture-handler
# Using yarn
yarn add react-native-gesture-handler
Linking (For React Native < 0.60)
If you're on a version of React Native below 0.60, you'll have to link the library manually:
react-native link react-native-gesture-handler
Additional Setup for iOS
For iOS, you must modify AppDelegate to include gesture handler support.
1. Open ios/[your_project]/AppDelegate.m.
2. Import the gesture handler:
#import <RNGestureHandler/RNGestureHandler.h>
3. Modify the didFinishLaunchingWithOptions method:
(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[RNGestureHandler enabled];
// ... other code
}
react-native-gesture-handler offers several benefits over the default gesture system in React Native.
Wrap Your App with GestureHandlerRootView
To make sure gesture handlers are working correctly, wrap your app's root component with GestureHandlerRootView.
// App.js
import React from 'react';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import Main from './Main'; // Your main component
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<Main />
</GestureHandlerRootView>
);
}
Basic Gesture Handling
With the setup, let's jump into some very basic gesture-handling examples with react-native-gesture-handler.
Tap Gesture Example
A tap is one of the easiest gestures to implement. Below is how you can create a component that listens for tap gestures.
// TapGestureExample.js
import React from 'react';
import { View, Text, StyleSheet, Alert } from 'react-native';
import { TapGestureHandler, State } from 'react-native-gesture-handler';
export default function TapGestureExample() {
const onSingleTap = (event) => {
if (event.nativeEvent.state === State.ACTIVE) {
Alert.alert('Single Tap', 'You tapped the box!');
}
};
return (
<View style={styles.container}>
<TapGestureHandler
onHandlerStateChange={onSingleTap}
numberOfTaps={1}
>
<View style={styles.box}>
<Text>Tap Me</Text>
</View>
</TapGestureHandler>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
box: {
width: 150,
height: 150,
backgroundColor: '#f0f0f0', // Light gray color
justifyContent: 'center',
alignItems: 'center',
borderRadius: 10,
},
});
Explanation
TapGestureHandler: It can recognize the tap gestures.
onHandlerStateChange: A callback that is called when the state of the gesture changes.
numberOfTaps: The number of taps necessary to activate the gesture is specified. Examples include single tap and double tap.
When the user taps the box, an alert is shown.
Pan Gesture Example
Pan gestures detect dragging movements. Let's create a draggable box.
import React, { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
export default function PanGestureExample() {
const [translate, setTranslate] = useState({ x: 0, y: 0 });
const onGestureEvent = (event) => {
setTranslate({
x: event.nativeEvent.translationX,
y: event.nativeEvent.translationY,
});
};
const onHandlerStateChange = (event) => {
if (event.nativeEvent.state === State.END) {
setTranslate({
x: translate.x + event.nativeEvent.translationX,
y: translate.y + event.nativeEvent.translationY,
});
}
};
return (
<View style={styles.container}>
<PanGestureHandler
onGestureEvent={onGestureEvent}
onHandlerStateChange={onHandlerStateChange}
>
<View style={[styles.box, { transform: [{ translateX: translate.x }, { translateY: translate.y }] }]}>
<Text>Drag Me</Text>
</View>
</PanGestureHandler>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
box: {
width: 150,
height: 150,
backgroundColor: '#a0c4ff', // Light blue color
justifyContent: 'center',
alignItems: 'center',
borderRadius: 10,
},
});
Explanation:
PanGestureHandler: Detects panning (dragging) gestures.
onGestureEvent: Called continuously as the user moves their finger.
onHandlerStateChange: Handles state changes, such as when the gesture ends.
Dragging the box across the screen with a translation to update its position based on that gesture.
Configuring Gestures
The usefulness of basic gestures aside, one can create quite complex interactions and customise according to the app's needs through customising gestures. Let us get into building a custom draggable component and integrating multiple gestures into that.
With the reusable draggable component, you are able to save time and get consistency throughout your app. Let's do that.
import React, { useState } from 'react';
import { StyleSheet, Animated, View, Text } from 'react-native';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
export default function DraggableBox() {
const [translate, setTranslate] = useState(new Animated.ValueXY());
const onGestureEvent = Animated.event(
[
{
nativeEvent: {
translationX: translate.x,
translationY: translate.y,
},
},
],
{ useNativeDriver: true }
);
const onHandlerStateChange = (event) => {
if (event.nativeEvent.oldState === State.ACTIVE) {
Animated.spring(translate, {
toValue: { x: 0, y: 0 },
useNativeDriver: true,
}).start();
}
};
return (
<View style={styles.container}>
<PanGestureHandler
onGestureEvent={onGestureEvent}
onHandlerStateChange={onHandlerStateChange}
>
<Animated.View style={[styles.box, { transform: translate.getTranslateTransform() }]}>
<Text>Drag Me</Text>
</Animated.View>
</PanGestureHandler>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
box: {
width: 150,
height: 150,
backgroundColor: '#ffadad', // Light red color
justifyContent: 'center',
alignItems: 'center',
borderRadius: 10,
},
});
Explanation:Animated.ValueXY: animated values for the X and Y axes.
Animated.event: It maps gesture events to animated values.
Animated.View: Animated version of the View component that listens to animated values.
transform: translate.getTranslateTransform(): Applies the animated translation to the view component.
This part can move the box all around by just dragging it there, and on releasing it springs back to where it originally lies.
Combining Multiple Gestures
Sometimes you want to capture more than one gesture on the same component. You may wish to capture tap and pan on the same box. Here is how to do it.
import React, { useState } from 'react';
import { View, Text, StyleSheet, Alert } from 'react-native';
import { PanGestureHandler, TapGestureHandler, State } from 'react-native-gesture-handler';
export default function CombinedGesturesExample() {
const [translate, setTranslate] = useState({ x: 0, y: 0 });
const onSingleTap = (event) => {
if (event.nativeEvent.state === State.ACTIVE) {
Alert.alert('Tap Detected', 'You tapped the box!');
}
};
const onPanGestureEvent = (event) => {
setTranslate({
x: event.nativeEvent.translationX,
y: event.nativeEvent.translationY,
});
};
const onPanHandlerStateChange = (event) => {
if (event.nativeEvent.state === State.END) {
setTranslate({
x: translate.x + event.nativeEvent.translationX,
y: translate.y + event.nativeEvent.translationY,
});
}
};
return (
<View style={styles.container}>
<TapGestureHandler onHandlerStateChange={onSingleTap} numberOfTaps={1}>
<PanGestureHandler
onGestureEvent={onPanGestureEvent}
onHandlerStateChange={onPanHandlerStateChange}
>
<View style={[styles.box, { transform: [{ translateX: translate.x }, { translateY: translate.y }] }]}>
<Text>Tap or Drag Me</Text>
</View>
</PanGestureHandler>
</TapGestureHandler>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
box: {
width: 150,
height: 150,
backgroundColor: '#caffbf', // Light green color
justifyContent: 'center',
alignItems: 'center',
borderRadius: 10,
},
});
Explanation:
Gesture Handler Nesting: The TapGestureHandler is used to wrap around the PanGestureHandler so that both gestures are recognized.
It intelligently manages gesture conflicts, such that a tap does not interfere with a pan gesture and vice versa.
In this configuration, the box will react to tap as well as drag events.
Consider the following best practices when implementing gesture handling using react-native-gesture-handler.
This requires effectively handling gestures when creating engaging and responsive mobile applications. The react-native-gesture-handler library is very robust and flexible in managing both simple and complex gestures in React Native. By knowing and customizing gesture handlers, you can build intuitive interactions to enhance the user experience.
Whether you're implementing basic taps and swipes or building intricate gesture-based interactions, react-native-gesture-handler offers the tools you need to bring your app to life. Start experimenting with different gestures and combinations to discover the full potential of gesture customization in your React Native projects.
Ready to transform your business with our technology solutions? Contact Us today to Leverage Our React Native Expertise.