React Native

Customizing Gesture Handling in React Native with GestureHandler


Introduction

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.

Why Use react-native-gesture-handler?

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.

  • Performance: Gestures will be handled on the native thread, so there will be more fluid and interactive responses.
  • Customizability: It enables the creation of complex gesture interactions by combining different gesture handlers.
  • Cross-Platform Support: It works flawlessly on both iOS and Android, handling platform-specific nuances.

Setting Up react-native-gesture-handler

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.jsimport React from 'react';import { GestureHandlerRootView } from 'react-native-gesture-handler';import Main from './Main'; // Your main componentexport 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.jsimport 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.

Best Practices

Consider the following best practices when implementing gesture handling using react-native-gesture-handler.

  • Animated for smooth transition: The Animated API can be used for animations that are dependent on gesture events, hence it's more fluid and performance-wise.
  • Manage Gesture Conflicts: When combining several gestures, be sure that none conflict. Make use of properties on gesture handlers such as simultaneousHandlers and waitFor to manage priority of gestures.
  • Optimize Performance: Use the useNativeDriver option wherever possible to offload animations to the native thread, thus making performance smoother.
  • Provide feedback: Visual feedback can include scaling or color changes to show that a gesture has been recognized. Test on Various Devices: Gestures may vary from device to device and from screen to screen. Test in an absolutely proper way.

Conclusion

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.

 

0

React Native

Related Center Of Excellence