--- title: Add gestures --- import { SnackInline, Terminal } from '~/ui/components/Snippet'; import Video from '~/components/plugins/Video'; import { A } from '~/ui/components/Text'; Gestures are a great way to provide an intuitive user experience in an app. The [React Native Gesture Handler library](https://docs.swmansion.com/react-native-gesture-handler/docs/) provides built-in native components that can handle gestures. It uses the platform's native touch handling system to recognize pan, tap, rotation, and other gestures. In this chapter, we are going to add two different gestures using the React Native Gesture Handler library: - Double tap to scale the size of the emoji sticker. - Pan to move the emoji sticker around the screen so that the user can place the sticker anywhere on the image. ## Step 1: Install and configure libraries The React Native Gesture Handler library provides a way to interact with the native platform's gesture response system. To animate between gesture states, we will use the [Reanimated library](https://docs.swmansion.com/react-native-reanimated/docs/). To install them, stop the development server by pressing Ctrl + c and run the following command in the terminal: Next, also install `@babel/plugin-proposal-export-namespace-from`, which is required to configure the Reanimated library: Then, add Reanimated's Babel plugin to **babel.config.js**: {/* prettier-ignore */} ```jsx babel.config.js module.exports = function (api) { api.cache(true); return { presets: ['babel-preset-expo'], /* @info Add the plugins array and inside it, add the plugins.*/ plugins: [ "@babel/plugin-proposal-export-namespace-from", "react-native-reanimated/plugin", ], /* @end */ }; }; ``` Now, start the development server again: > **Tip**: We are using `-c` option here because we modified the **babel.config.js** file. To get gesture interactions to work in the app, we'll render `` from `react-native-gesture-handler` to wrap the top-level component of our app (also known as the "root component"). To accomplish this, replace the root level `` component in the **App.js** with ``. {/* prettier-ignore */} ```jsx App.js /* @info Import GestureHandlerRootView from react-native-gesture-handler-library. */import { GestureHandlerRootView } from "react-native-gesture-handler"; /* @end */ export default function App() { return ( /* @info Replace the root level View component with GestureHandlerRootView. */ /* @end */ /* ...rest of the code remains */ /* @info *//* @end */ ) } ``` ## Step 2: Create animated components Open the **EmojiSticker.js** file in the **components** directory. Inside it, import `Animated` from the `react-native-reanimated` library to create animated components. ```jsx EmojiSticker.js import Animated from 'react-native-reanimated'; ``` To make a double tap gesture work, we will apply animations to the `` component by passing it as an argument to the `Animated.createAnimatedComponent()` method. ```jsx EmojiSticker.js // after import statements, add the following line const AnimatedImage = Animated.createAnimatedComponent(Image); ``` The `createAnimatedComponent()` can wrap any component. It looks at the `style` prop of the component, determines which value is animated, and then applies updates to create an animation. Replace the `` component with ``. {/* prettier-ignore */} ```jsx EmojiSticker.js export default function EmojiSticker({ imageSize, stickerSource }) { return ( /* @info Replace the Image component with AnimatedImage. */ ); } ``` ## Step 3: Add a tap gesture React Native Gesture Handler allows us to add behavior when it detects touch input, like a double tap event. In the **EmojiSticker.js** file, import `TapGestureHandler` from `react-native-gesture-handler` and the hooks below from `react-native-reanimated`. These hooks will animate the style on the `` component for the sticker when the tap gesture is recognized. ```jsx EmojiSticker.js import { TapGestureHandler } from 'react-native-gesture-handler'; import Animated, { useAnimatedStyle, useSharedValue, useAnimatedGestureHandler, withSpring, } from 'react-native-reanimated'; ``` Inside the `` component, create a reference called `scaleImage` using the `useSharedValue()` hook. It will take the value of `imageSize` as its initial value. ```jsx EmojiSticker.js const scaleImage = useSharedValue(imageSize); ``` Creating a shared value using the `useSharedValue()` hook has many advantages. It helps to mutate a piece of data and allows running animations based on the current value. A shared value can be accessed and modified using the `.value` property. It will scale the initial value of `scaleImage` so that when a user double-taps the sticker, it scales to twice its original size. To do this, we will create a function and call it `onDoubleTap()`, and this function will use the `useAnimatedGestureHandler()` hook to animate the transition while scaling the sticker image. Create the following function in the `` component: ```jsx EmojiSticker.js const onDoubleTap = useAnimatedGestureHandler({ onActive: () => { if (scaleImage.value) { scaleImage.value = scaleImage.value * 2; } }, }); ``` To animate the transition, let's use a spring-based animation. This will make it feel alive because it's based on the real-world physics of a spring. We will use the `withSpring()` hook provided by `react-native-reanimated`. The `useAnimatedStyle()` hook from `react-native-reanimated` is used to create a style object that will be applied to the sticker image. It will update styles using the shared values when the animation happens. In this case, we are scaling the size of the image, which is done by manipulating the `width` and `height` properties. The initial values of these properties are set to `imageSize`. Create an `imageStyle` variable and add it to the `EmojiSticker` component: ```jsx EmojiSticker.js const imageStyle = useAnimatedStyle(() => { return { width: withSpring(scaleImage.value), height: withSpring(scaleImage.value), }; }); ``` Next, wrap the `` component that displays the sticker on the screen with the `` component. {/* prettier-ignore */} ```jsx export default function EmojiSticker({ imageSize, stickerSource }) { // ...rest of the code remains same return ( /* @info Wrap the AnimatedImage component with TapGestureHandler*/ /* @end */ /* @info *//* @end */ ); } ``` In the above snippet, the `onGestureEvent` prop takes the value of the `onDoubleTap()` function and triggers it when a user taps the sticker image. The `numberOfTaps` prop determines how many taps are required. Let's take a look at our app on iOS, Android and the web: