this repo has no description
1# react-native-gesture-handler
2
3### Overview
4
5The **React Native Gesture Handler** offers a declarative API that exposes the native touch and gesture systems to React Native applications.
6
7#### How It Works
8
9Explore its functionality by tapping and dragging circles to understand various gestures.
10
11### Reasons to Use Gesture Handler
12
13- **Native Gesture Recognizers**: Utilizes platform-specific APIs for handling touch streams on the UI thread.
14
15- **Native Components**: Includes components like `SwipeableRow` or `Drawer` designed for optimal interactions.
16
17- **High Performance (120 FPS)**: Integrates with Reanimated to enable smooth gesture-based experiences at up to 120 frames per second.
18
19For more details, refer to the latest article on Gesture Handler features and check out related blog posts.
20
21### About Software Mansion
22
23Software Mansion is a team of React Native Core Contributors and experts specializing in resolving various React Native challenges. Whether you need assistance with gestures, animations, or general development, we are here to help.
24
25## Installation
26
27### Requirements
28
29The `react-native-gesture-handler` library supports the three most recent minor versions of `react-native`. Below is a compatibility table:
30
31|Gesture Handler Version|React Native Version|
32|-|-|
33|2.24.0+|0.75.0+|
34|2.21.0+|0.74.0+|
35|2.18.0+|0.73.0+|
36|2.16.0+|0.68.0+|
37|2.14.0+|0.67.0+|
38|2.10.0+|0.64.0+|
39|2.0.0+|0.63.0+|
40
41To fully leverage touch events, ensure you are using `react-native-reanimated` version 2.3.0 or newer.
42
43#### Installation Steps
44
45##### Step 1: Install the Package
46
47Choose one of the following methods to install:
48
49- **EXPO**
50
51 ```bash
52 npx expo install react-native-gesture-handler
53 ```
54
55- **NPM**
56
57 ```bash
58 npm install react-native-gesture-handler
59 ```
60
61- **YARN**
62
63 ```bash
64 yarn add react-native-gesture-handler
65 ```
66
67##### Step 2: Wrap Your App with `GestureHandlerRootView`
68
69```typescript
70import { GestureHandlerRootView } from 'react-native-gesture-handler';
71
72export default function App() {
73 return (
74 <GestureHandlerRootView>
75 <ActualApp />
76 </GestureHandlerRootView>
77 );
78}
79```
80
81- If no styles are provided, it defaults to `flex: 1`. Ensure custom styles include `flex: 1` to render your app correctly.
82- Place `GestureHandlerRootView` as close to the root of your application as possible. Gestures outside this view won't be recognized.
83
84**Tip:** For component libraries using gesture handlers, wrap the library code with `GestureHandlerRootView`.
85
86##### Step 3: Platform-Specific Setup
87
88###### Expo Development Build
89
90For Expo development builds, update native code in iOS and Android directories:
91
92```bash
93npx expo prebuild
94```
95
96###### Android
97
98No additional steps are required for Android. For gestures within Modals, wrap the content with `GestureHandlerRootView`:
99
100```typescript
101import { Modal } from 'react-native';
102import { GestureHandlerRootView } from 'react-native-gesture-handler';
103
104export function CustomModal({ children, ...rest }) {
105 return (
106 <Modal {...rest}>
107 <GestureHandlerRootView>
108 {children}
109 </GestureHandlerRootView>
110 </Modal>
111 );
112}
113```
114
115###### Kotlin
116
117To specify a Kotlin version for Gesture Handler on Android, set the `kotlinVersion` in your `android/build.gradle`:
118
119```groovy
120buildscript {
121 ext {
122 kotlinVersion = "1.6.21"
123 }
124}
125```
126
127###### iOS
128
129Before running your app during development, install pods:
130
131```bash
132cd ios && pod install && cd ..
133```
134
135###### Web
136
137No additional configuration is needed for the web. From version 2.10.0, a new implementation is enabled by default. Verify gesture behavior matches native platforms. To revert to the legacy implementation, add this at the start of your `index.js`:
138
139```typescript
140import { enableLegacyWebImplementation } from "react-native-gesture-handler"
141
142enableLegacyWebImplementation(true)
143```
144
145Adapting to the new implementation is recommended as the legacy version will be deprecated in future releases.
146
147###### With wix/react-native-navigation
148
149When using native navigation libraries like `wix/react-native-navigation`, ensure each screen is wrapped with `GestureHandlerRootView` using `gestureHandlerRootHOC`. This can be done during screen registration:
150
151```typescript
152import { gestureHandlerRootHOC } from "react-native-gesture-handler"
153import { Navigation } from "react-native-navigation"
154import FirstTabScreen from "./FirstTabScreen"
155import SecondTabScreen from "./SecondTabScreen"
156import PushedScreen from "./PushedScreen"
157
158export function registerScreens() {
159 Navigation.registerComponent(
160 "example.FirstTabScreen",
161 () => gestureHandlerRootHOC(FirstTabScreen),
162 () => FirstTabScreen
163 )
164 Navigation.registerComponent(
165 "example.SecondTabScreen",
166 () => gestureHandlerRootHOC(SecondTabScreen),
167 () => SecondTabScreen
168 )
169 Navigation.registerComponent(
170 "example.PushedScreen",
171 () => gestureHandlerRootHOC(PushedScreen),
172 () => PushedScreen
173 )
174}
175```
176
177Ensure each screen in your app is wrapped with `GestureHandlerRootView` as native navigation libraries map each screen to a separate root view.
178
179## Rotation gesture
180
181A continuous gesture capable of recognizing and tracking rotation movements. Activation occurs when fingers are placed on the screen and move in a specific manner.
182
183The gesture callback facilitates ongoing monitoring, providing details such as the degree of rotation, the focal point (anchor), and instantaneous velocity.
184
185### Example
186
187```typescript
188import { StyleSheet } from 'react-native';
189import { Gesture, GestureDetector } from 'react-native-gesture-handler';
190import Animated, {
191 useSharedValue,
192 useAnimatedStyle,
193} from 'react-native-reanimated';
194
195export default function App() {
196 const rotation = useSharedValue(1);
197 const savedRotation = useSharedValue(1);
198
199 const rotationGesture = Gesture.Rotation()
200 .onUpdate((e) => {
201 rotation.value = savedRotation.value + e.rotation;
202 })
203 .onEnd(() => {
204 savedRotation.value = rotation.value;
205 });
206
207 const animatedStyle = useAnimatedStyle(() => ({
208 transform: [{ rotateZ: `${(rotation.value / Math.PI) * 180}deg` }],
209 }));
210
211 return (
212 <GestureDetector gesture={rotationGesture}>
213 <Animated.View style={[styles.box, animatedStyle]} />
214 </GestureDetector>
215 );
216}
217
218const styles = StyleSheet.create({
219 box: {
220 height: 120,
221 width: 120,
222 backgroundColor: '#b58df1',
223 borderRadius: 20,
224 marginBottom: 30,
225 },
226});
227```
228
229### Configuration
230
231#### Properties Common to All Gestures:
232
233- **`enabled(value: boolean)`**: Determines if the handler analyzes touch events. Default is `true`. Setting it to `false` ensures the handler never becomes `ACTIVE`.
234
235- **`shouldCancelWhenOutside(value: boolean)`**: Cancels or fails recognition when fingers leave the view area. Defaults vary by gesture type.
236
237- **`hitSlop(settings)`**: Adjusts the active area for gesture recognition. Supports negative values and specific boundary adjustments (`left`, `right`, `top`, `bottom`, `horizontal`, `vertical`, `width`, `height`). Primarily reduces the activation area, with Android supporting positive expansions within parent bounds.
238
239- **`withRef(ref)`**: Sets a ref to the gesture object for interoperability with older APIs.
240
241- **`withTestId(testID)`**: Assigns a `testID` for querying in tests.
242
243- **`cancelsTouchesInView(value)`** (**iOS only**): Cancels touches for native UI components when active. Default is `true`.
244
245- **`runOnJS(value: boolean)`**: Determines if callbacks run on the JS thread instead of the UI thread. Defaults to `false`.
246
247- **`simultaneousWithExternalGesture(otherGesture1, otherGesture2, ...)`**: Marks gestures to be recognized simultaneously without composing them.
248
249- **`requireExternalGestureToFail(otherGesture1, otherGesture2, ...)`**: Requires another gesture to fail before activation.
250
251- **`blocksExternalGesture(otherGesture1, otherGesture2, ...)`**: Delays other gestures until this one fails or doesn't start. Marks relations without composing them.
252
253- **`activeCursor(value)`** (Web only): Specifies the cursor style when active. Supports CSS cursor values. Default is `"auto"`.
254
255#### Properties Common to All Continuous Gestures:
256
257- **`manualActivation(value: boolean)`**: Disables automatic activation, allowing manual state management.
258
259### Callbacks
260
261#### Common to All Gestures:
262
263- **`onBegin(callback)`**: Triggered when the gesture handler starts receiving touches but hasn't yet recognized a gesture.
264
265- **`onStart(callback)`**: Called when the gesture is recognized and transitions to an active state.
266
267- **`onEnd(callback)`**: Invoked when the recognized gesture finishes, provided it was previously active.
268
269- **`onFinalize(callback)`**: Executed upon finalizing gesture handling, whether recognized or failed.
270
271- **`onTouchesDown(callback)`**: Triggered each time a finger touches the screen.
272
273- **`onTouchesMove(callback)`**: Called whenever a finger moves on the screen.
274
275- **`onTouchesUp(callback)`**: Invoked when a finger is lifted from the screen.
276
277- **`onTouchesCancelled(callback)`**: Executed when touch tracking stops, such as gesture completion.
278
279#### Common to All Continuous Gestures:
280
281- **`onUpdate(callback)`**: Called with every update during active gesture recognition.
282
283- **`onChange(callback)`**: Triggered with updates, providing change information relative to the last event.
284
285### Event Data
286
287#### Specific to `RotationGesture`:
288
289- **`rotation`**: Rotation amount in radians from the focal point (anchor).
290
291- **`velocity`**: Instantaneous velocity in points per second.
292
293- **`anchorX`**: X coordinate of the gesture's central focal point (anchor) in points.
294
295- **`anchorY`**: Y coordinate of the gesture's central focal point (anchor) in points.
296
297#### Common to All Gestures:
298
299- **`state`**: Current handler state, expressed as a constant from the `State` object.
300
301- **`numberOfPointers`**: Number of fingers currently on the screen.
302
303- **`pointerType`**: Type of pointer device, represented by the `PointerType` enum (`TOUCH`, `STYLUS`, `MOUSE`, `KEY`, `OTHER`).
304
305## Pinch gesture
306
307A continuous gesture that recognizes pinch gestures, allowing for tracking the distance between two fingers to scale or zoom content. The gesture activates when fingers are placed on the screen and change their position. A callback can be used for continuous tracking of the pinch gesture, providing information about velocity, anchor (focal) point, and scale.
308
309The distance between the fingers is reported as a scale factor. At the beginning of the gesture, the scale factor is 1.0. As the distance between two fingers increases, the scale factor increases proportionally; it decreases as the distance reduces. Pinch gestures are commonly used to change the size of objects or content onscreen, such as adjusting the zoom level of map views.
310
311### Example
312
313```typescript
314import { StyleSheet } from 'react-native';
315import { Gesture, GestureDetector } from 'react-native-gesture-handler';
316import Animated, {
317 useSharedValue,
318 useAnimatedStyle,
319} from 'react-native-reanimated';
320
321export default function App() {
322 const scale = useSharedValue(1);
323 const savedScale = useSharedValue(1);
324
325 const pinchGesture = Gesture.Pinch()
326 .onUpdate((e) => {
327 scale.value = savedScale.value * e.scale;
328 })
329 .onEnd(() => {
330 savedScale.value = scale.value;
331 });
332
333 const animatedStyle = useAnimatedStyle(() => ({
334 transform: [{ scale: scale.value }],
335 }));
336
337 return (
338 <GestureDetector gesture={pinchGesture}>
339 <Animated.View style={[styles.box, animatedStyle]} />
340 </GestureDetector>
341 );
342}
343
344const styles = StyleSheet.create({
345 box: {
346 height: 120,
347 width: 120,
348 backgroundColor: '#b58df1',
349 borderRadius: 20,
350 marginBottom: 30,
351 },
352});
353```
354
355### Configuration
356
357#### Properties Common to All Gestures:
358
359|Property|Description|
360|-|-|
361|`enabled(value: boolean)`|Indicates whether the handler should analyze touch events. Default is `true`. If set to `false`, the handler's state will never become `ACTIVE`.|
362|`shouldCancelWhenOutside(value: boolean)`|When `true`, cancels or fails recognition if a finger leaves the view area. Defaults vary by gesture type; most are `false` except for `LongPressGesture` and `TapGesture`, which default to `true`.|
363|`hitSlop(settings)`|Controls the activation area of the gesture within the connected view. Negative numbers reduce bounds evenly, while objects can specify reductions per side or edge. Positive values on Android expand beyond view bounds but not past parent view bounds. Use React Native's View hitSlop for cross-platform support.|
364|`withRef(ref)`|Sets a ref to the gesture object for interoperability with older APIs.|
365|`withTestId(testID)`|Assigns a `testID` property for querying in tests.|
366|`cancelsTouchesInView(value)` (**iOS only**)|When `true`, cancels touches for native UI components when active. Default is `true`.|
367|`runOnJS(value: boolean)`|Determines if callbacks run on the JS thread (`true`) or UI thread (`false`). Defaults to `false` with `react-native-reanimated`.|
368|`simultaneousWithExternalGesture(otherGesture1, otherGesture2, ...)`|Marks gestures for simultaneous recognition without composing them. Requires additional detectors for recognition.|
369|`requireExternalGestureToFail(otherGesture1, otherGesture2, ...)`|Adds a relation requiring another gesture to fail before activation. Does not compose gestures; requires additional detectors.|
370|`blocksExternalGesture(otherGesture1, otherGesture2, ...)`|Makes other gestures wait until this one fails or doesn't start. Marks relations without composing gestures; requires additional detectors.|
371|`activeCursor(value)` (**Web only**)|Specifies the cursor when the gesture activates. Supports CSS cursor values (e.g., `"grab"`, `"zoom-in"`). Default is `"auto"`.|
372
373#### Properties Common to All Continuous Gestures:
374
375- **`manualActivation(value: boolean)`**: When `true`, prevents automatic activation even if criteria are met, allowing manual state manipulation.
376
377### Callbacks
378
379#### Callbacks Common to All Gestures:
380
381|Callback|Description|
382|-|-|
383|`onBegin(callback)`|Called when the gesture handler starts receiving touches but is not yet active.|
384|`onStart(callback)`|Called when the gesture is recognized and transitions to an active state.|
385|`onEnd(callback)`|Called when a recognized gesture finishes, provided it was previously active.|
386|`onFinalize(callback)`|Called when handling finalizes—either recognition completes or fails.|
387|`onTouchesDown(callback)`|Triggered every time a finger is placed on the screen.|
388|`onTouchesMove(callback)`|Triggered every time a finger moves on the screen.|
389|`onTouchesUp(callback)`|Triggered every time a finger is lifted from the screen.|
390|`onTouchesCancelled(callback)`|Triggered when a finger stops being tracked, such as when a gesture finishes.|
391
392#### Callbacks Common to All Continuous Gestures:
393
394- **`onUpdate(callback)`**: Called with each update while the gesture is active.
395- **`onChange(callback)`**: Called with updates during activity, providing change information relative to the last event.
396
397### Event Data
398
399#### Attributes Specific to `PinchGesture`:
400
401|Attribute|Description|
402|-|-|
403|`scale`|Scale factor relative to touch points in screen coordinates.|
404|`velocity`|Velocity of the gesture at the current moment, expressed as scale factor per second.|
405|`focalX`|X-axis position of the center anchor point of the gesture in points.|
406|`focalY`|Y-axis position of the center anchor point of the gesture in points.|
407
408#### Attributes Common to All Gestures:
409
410|Attribute|Description|
411|-|-|
412|`state`|Current state of the handler, expressed as a constant from the `State` object.|
413|`numberOfPointers`|Number of pointers (fingers) currently on the screen.|
414|`pointerType`|Type of pointer device in use, represented by the `PointerType` enum: `TOUCH`, `STYLUS`, `MOUSE`, `KEY`, or `OTHER`.|
415
416## Force Touch Gesture
417
418A continuous gesture that recognizes the force of a touch, allowing for tracking pressure on some iOS devices. The gesture activates when the touch force is greater than or equal to `minForce` and fails if it exceeds `maxForce`. A callback can be used for continuous tracking of touch pressure, providing information for one finger (the first one).
419
420At the beginning of the gesture, the pressure factor is 0.0, increasing proportionally with pressure up to a maximum of 1.0.
421
422There's no implementation on Android; it simply renders children without any wrappers. Since this behavior is only available on some iOS devices, this gesture should not be used for defining crucial behaviors. Use it as an additional improvement and ensure all features are accessible without this gesture.
423
424### Reference
425
426```typescript
427import { GestureDetector, Gesture } from 'react-native-gesture-handler';
428
429function App() {
430 const forceTouch = Gesture.ForceTouch();
431
432 return (
433 <GestureDetector gesture={forceTouch}>
434 <View />
435 </GestureDetector>
436 );
437}
438```
439
440### Configuration
441
442#### Properties Specific to `ForceTouchGesture`:
443
444|Property|Description|
445|-|-|
446|`minForce(value: number)`|Minimal pressure required for activation. Range `[0.0, 1.0]`. Default is `0.2`.|
447|`maxForce(value: number)`|Maximal pressure before gesture fails. Range `[0.0, 1.0]`.|
448|`feedbackOnActivation(value: boolean)`|Defines if haptic feedback occurs on activation.|
449
450#### Properties Common to All Gestures:
451
452|Property|Description|
453|-|-|
454|`enabled(value: boolean)`|Indicates whether the handler analyzes touch events. Default is `true`.|
455|`shouldCancelWhenOutside(value: boolean)`|Cancels recognition if finger leaves view area. Defaults vary by handler type.|
456|`hitSlop(settings)`|Controls gesture activation area within the view. Supports negative values for reduction.|
457|`withRef(ref)`|Sets a ref to the gesture object for interoperability with old API.|
458|`withTestId(testID)`|Sets a `testID` property for querying in tests.|
459|`cancelsTouchesInView(value)` (**iOS only**)|Cancels touches for native UI components when active. Default is `true`.|
460|`runOnJS(value: boolean)`|Runs callbacks on JS thread if true, otherwise on the UI thread. Defaults to `false`.|
461|`simultaneousWithExternalGesture(otherGesture1, otherGesture2, ...)`|Marks relation for simultaneous recognition with other gestures.|
462|`requireExternalGestureToFail(otherGesture1, otherGesture2, ...)`|Requires another gesture to fail before activation.|
463|`blocksExternalGesture(otherGesture1, otherGesture2, ...)`|Makes other gestures wait until this one fails or doesn't start.|
464|`activeCursor(value)` (**Web only**)|Specifies cursor when gesture activates. Supports CSS cursor values. Default is `"auto"`.|
465
466#### Properties Common to All Continuous Gestures:
467
468|Property|Description|
469|-|-|
470|`manualActivation(value: boolean)`|When true, the handler does not activate automatically; state must be manipulated manually.|
471
472### Callbacks
473
474#### Callbacks Common to All Gestures:
475
476|Callback|Description|
477|-|-|
478|`onBegin(callback)`|Called when gesture handling starts receiving touches.|
479|`onStart(callback)`|Called when the gesture is recognized and transitions to active state.|
480|`onEnd(callback)`|Called when a recognized gesture finishes, if previously in active state.|
481|`onFinalize(callback)`|Called when gesture handling finalizes (recognized or failed).|
482|`onTouchesDown(callback)`|Called every time a finger is placed on the screen.|
483|`onTouchesMove(callback)`|Called every time a finger moves on the screen.|
484|`onTouchesUp(callback)`|Called every time a finger is lifted from the screen.|
485|`onTouchesCancelled(callback)`|Called when a finger stops being tracked, e.g., gesture finishes.|
486
487#### Callbacks Common to All Continuous Gestures:
488
489|Callback|Description|
490|-|-|
491|`onUpdate(callback)`|Called every time the gesture receives an update while active.|
492|`onChange(callback)`|Called with information about changes in value relative to the last event.|
493
494### Event Data
495
496#### Attributes Specific to `ForceTouchGesture`:
497
498|Attribute|Description|
499|-|-|
500|`force`|The pressure of a touch.|
501
502#### Attributes Common to All Gestures:
503
504|Attribute|Description|
505|-|-|
506|`state`|Current state of the handler, expressed as one of the constants in the `State` object.|
507|`numberOfPointers`|Number of pointers (fingers) currently on the screen.|
508|`pointerType`|Type of pointer device in use, represented by the `PointerType` enum (`TOUCH`, `STYLUS`, etc.).|
509
510## Buttons
511
512The Gesture Handler library provides native components that function as buttons, serving as alternatives to `TouchableHighlight` or `TouchableOpacity` from React Native (RN) core. These gesture handler buttons recognize touches natively, ensuring a deterministic recognition process and enabling highly performant ripple effects on Android (`TouchableNativeFeedback` requires touch events to return to JavaScript before updating the ripple effect, causing lag on older devices). Additionally, they offer native and platform-specific interactions for buttons within scrollable containers, slightly delaying interaction to prevent premature highlighting during flinging.
513
514The library currently exposes three components that render native touchable elements:
515
516- `BaseButton`
517- `RectButton`
518- `BorderlessButton`
519
520All buttons are wrapped with `NativeViewGestureHandler`, allowing the application of common gesture handler properties and additional properties specific to `NativeViewGestureHandler`.
521
522**IMPORTANT**: To ensure button accessibility, wrap children in a `View` with `accessible` and `accessibilityRole="button"` props. Example:
523
524```tsx
525// Not accessible:
526const NotAccessibleButton = () => (
527 <RectButton onPress={this._onPress}>
528 <Text>Foo</Text>
529 </RectButton>
530)
531
532// Accessible:
533const AccessibleButton = () => (
534 <RectButton onPress={this._onPress}>
535 <View accessible accessibilityRole="button">
536 <Text>Bar</Text>
537 </View>
538 </RectButton>
539)
540```
541
542This is applicable to both iOS and Android platforms. On iOS, inaccessible buttons cannot be selected; on Android, they cannot be clicked in accessibility mode.
543
544### `BaseButton`
545
546`BaseButton` can serve as a base class for implementing custom interactions when the button is pressed.
547
548#### Properties specific to `BaseButton`:
549
550- **onActiveStateChange**: A function triggered when the button transitions between active and inactive states. It receives the active state as a boolean parameter.
551
552- **onPress**: A function triggered upon pressing the button, similar to `onPress` in `TouchableHighlight`.
553
554- **onLongPress**: A function triggered if the button is pressed for at least `delayLongPress` milliseconds.
555
556- **rippleColor** (**Android only**): Defines the color of the native ripple animation used since API level 21.
557
558- **exclusive**: Determines whether more than one button can be pressed simultaneously. Default is `true`.
559
560- **delayLongPress**: The delay, in milliseconds, before the `onLongPress` callback is invoked. Default is 600.
561
562### `RectButton`
563
564Use `RectButton` for rectangular elements or content blocks that are pressable, such as table rows or buttons with text and icons. It provides platform-specific interactions: a rectangular ripple on Android, background highlighting on iOS, and similar effects on older Android versions. In addition to `BaseButton` properties, it includes:
565
566#### Properties specific to `RectButton`:
567
568- **underlayColor**: The background color dimmed when the button is active.
569
570- **activeOpacity** (**iOS only**): The opacity applied to the underlay during the active state.
571
572### `BorderlessButton`
573
574Use `BorderlessButton` for simple icon-only or text-only buttons. Interaction varies by platform: a borderless ripple on Android and background dimming on iOS, similar to `TouchableOpacity`. In addition to `BaseButton` properties, it includes:
575
576#### Properties specific to `BorderlessButton`:
577
578- **borderless** (**Android only**): Set to `false` if the ripple should be confined within view bounds.
579
580- **activeOpacity** (**iOS only**): The opacity applied during the active state.
581
582### Design Patterns
583
584These components are not designed to behave identically across platforms but rather to handle similar behaviors on iOS and Android, considering their design concepts. For platform-specific design patterns, refer to official Apple documentation and Material.io guidelines.
585
586The library supports using native components with native feedback in appropriate situations. If a custom design approach is unnecessary, `RectButton` and `BorderlessButton` are sufficient. Otherwise, rely on `BaseButton`, which can be customized for specific needs.
587
588#### Common Use Cases
589
590- **Lists and Action Buttons**: Use `RectButton` for list items or action buttons that appear as separate UI blocks. It changes opacity on click and supports a ripple effect on Android. Emphasis is achieved through fill color or transparency, with outlined buttons used for medium emphasis.
591
592- **Icon or Text Only Buttons**: Use `BorderlessButton` for simple icon-only or text-only buttons. Interaction varies by platform: borderless ripple on Android and dimming on iOS. Suitable for non-crucial actions.
593
594#### `PureNativeButton`
595
596For more complex button implementations, use `PureNativeButton` to access the native component. It is generally not recommended but can be useful when wrapping with Animated or Reanimated:
597
598```tsx
599import {
600 createNativeWrapper,
601 PureNativeButton,
602} from "react-native-gesture-handler"
603import Animated from "react-native-reanimated"
604
605const { event, Value, createAnimatedComponent } = Animated
606
607const AnimatedRawButton = createNativeWrapper(
608 createAnimatedComponent(PureNativeButton),
609 {
610 shouldCancelWhenOutside: false,
611 shouldActivateOnStart: false,
612 }
613)
614
615export default class App extends React.Component {
616 constructor(props) {
617 super(props)
618 const state = new Value()
619 this._onGestureEvent = event([
620 {
621 nativeEvent: { state },
622 },
623 ])
624 }
625
626 render() {
627 return <AnimatedRawButton onHandlerStateChange={this._onGestureEvent} />
628 }
629}
630```
631
632## Pan gesture
633
634A pan gesture recognizes and tracks a continuous dragging motion. It activates when a finger touches the screen and moves beyond an initial distance.
635
636Configurations include setting a minimum starting distance, specifying vertical or horizontal detection, and defining the number of fingers required for activation (supporting multifinger swipes). A callback function can be used to continuously track the gesture's movement, providing details such as XY translation from the start point and instantaneous velocity.
637
638### Example
639
640```typescript
641import { StyleSheet } from 'react-native';
642import { Gesture, GestureDetector } from 'react-native-gesture-handler';
643import Animated, {
644 useSharedValue,
645 withTiming,
646 useAnimatedStyle,
647} from 'react-native-reanimated';
648
649const END_POSITION = 200;
650
651export default function App() {
652 const onLeft = useSharedValue(true);
653 const position = useSharedValue(0);
654
655 const panGesture = Gesture.Pan()
656 .onUpdate((e) => {
657 if (onLeft.value) {
658 position.value = e.translationX;
659 } else {
660 position.value = END_POSITION + e.translationX;
661 }
662 })
663 .onEnd((e) => {
664 if (position.value < END_POSITION / 2) {
665 withTiming(0, { duration: 200 }, () => {
666 onLeft.value = true;
667 });
668 } else {
669 withTiming(END_POSITION, { duration: 200 }, () => {
670 onLeft.value = false;
671 });
672 }
673 });
674
675 const animatedStyle = useAnimatedStyle(() => ({
676 transform: [{ translateX: position.value }],
677 }));
678
679 return (
680 <GestureDetector gesture={panGesture}>
681 <Animated.View style={[styles.box, animatedStyle]} />
682 </GestureDetector>
683 );
684}
685
686const styles = StyleSheet.create({
687 box: {
688 width: 100,
689 height: 100,
690 backgroundColor: 'blue',
691 },
692});
693```
694
695### Multifinger Pan Gestures
696
697Multifinger pan gestures can be configured by setting the `minPointers` and `maxPointers` properties. This allows for specifying the minimum and maximum number of fingers required to activate the gesture.
698
699```typescript
700const multiFingerPanGesture = Gesture.Pan().minPointers(2).maxPointers(3)
701```
702
703### Event Data
704
705#### Pan Gesture Specific Attributes
706
707- `translationX`: Accumulated translation along the X-axis, in points.
708- `translationY`: Accumulated translation along the Y-axis, in points.
709- `velocityX`: Current velocity along the X-axis, in points per second.
710- `velocityY`: Current velocity along the Y-axis, in points per second.
711- `x`: X-coordinate of the pointer relative to the view, in points.
712- `y`: Y-coordinate of the pointer relative to the view, in points.
713- `absoluteX`: X-coordinate of the pointer relative to the window, in points.
714- `absoluteY`: Y-coordinate of the pointer relative to the window, in points.
715- `stylusData`: Additional stylus information including tilt angles and pressure.
716
717#### Common Attributes for All Gestures
718
719- `state`: Current state of the handler (e.g., active, failed).
720- `numberOfPointers`: Number of fingers currently on the screen.
721- `pointerType`: Type of pointer device (e.g., touch, stylus).
722
723### Callbacks
724
725#### Common to All Gestures
726
727- `onBegin(callback)`: Called when touches begin but before activation.
728- `onStart(callback)`: Called when the gesture is recognized and becomes active.
729- `onEnd(callback)`: Called when an active gesture ends.
730- `onFinalize(callback)`: Called after a gesture is finalized (recognized or failed).
731- `onTouchesDown(callback)`: Triggered when a finger touches down.
732- `onTouchesMove(callback)`: Triggered when a finger moves on the screen.
733- `onTouchesUp(callback)`: Triggered when a finger lifts off the screen.
734- `onTouchesCancelled(callback)`: Triggered when tracking stops (e.g., gesture ends).
735
736#### Common to Continuous Gestures
737
738- `onUpdate(callback)`: Called with each update during an active gesture.
739- `onChange(callback)`: Called with changes in value relative to the last event.
740
741### Configuration Properties
742
743#### Pan Gesture Specific
744
745- `minPointers(min: number)`: Minimum fingers required for activation.
746- `maxPointers(max: number)`: Maximum fingers allowed for activation.
747
748#### Common to All Gestures
749
750- `manualActivation(value: boolean)`: If true, manual state management is needed.
751- `simultaneousWithExternalGesture(otherGestures...)`: Recognizes gestures simultaneously with others.
752- `requireExternalGestureToFail(otherGestures...)`: Requires other gestures to fail before activation.
753- `blocksExternalGesture(otherGestures...)`: Blocks other gestures until this one fails or doesn't start.
754
755#### Platform-Specific
756
757- **iOS**: `cancelsTouchesInView(value: boolean)`: Cancels touches for native UI components when active.
758- **Web**: `activeCursor(cursorStyle: string)`: Sets the cursor style during activation.
759
760## Buttons
761
762The Gesture Handler library provides native components that function as buttons, serving as alternatives to `TouchableHighlight` or `TouchableOpacity` from React Native (RN) core. These gesture handler buttons recognize touches natively, ensuring a deterministic recognition process and enabling highly performant ripple effects on Android (`TouchableNativeFeedback` requires touch events to return to JavaScript before updating the ripple effect, causing lag on older devices). Additionally, they offer native and platform-specific interactions for buttons within scrollable containers, slightly delaying interaction to prevent premature highlighting during flinging.
763
764The library currently exposes three components that render native touchable elements:
765
766- `BaseButton`
767- `RectButton`
768- `BorderlessButton`
769
770All buttons are wrapped with `NativeViewGestureHandler`, allowing the application of common gesture handler properties and additional properties specific to `NativeViewGestureHandler`.
771
772**IMPORTANT**: To ensure button accessibility, wrap children in a `View` with `accessible` and `accessibilityRole="button"` props. Example:
773
774```tsx
775// Not accessible:
776const NotAccessibleButton = () => (
777 <RectButton onPress={this._onPress}>
778 <Text>Foo</Text>
779 </RectButton>
780)
781
782// Accessible:
783const AccessibleButton = () => (
784 <RectButton onPress={this._onPress}>
785 <View accessible accessibilityRole="button">
786 <Text>Bar</Text>
787 </View>
788 </RectButton>
789)
790```
791
792This is applicable to both iOS and Android platforms. On iOS, inaccessible buttons cannot be selected; on Android, they cannot be clicked in accessibility mode.
793
794### `BaseButton`
795
796`BaseButton` can serve as a base class for implementing custom interactions when the button is pressed.
797
798#### Properties specific to `BaseButton`:
799
800- **onActiveStateChange**: A function triggered when the button transitions between active and inactive states. It receives the active state as a boolean parameter.
801
802- **onPress**: A function triggered upon pressing the button, similar to `onPress` in `TouchableHighlight`.
803
804- **onLongPress**: A function triggered if the button is pressed for at least `delayLongPress` milliseconds.
805
806- **rippleColor** (**Android only**): Defines the color of the native ripple animation used since API level 21.
807
808- **exclusive**: Determines whether more than one button can be pressed simultaneously. Default is `true`.
809
810- **delayLongPress**: The delay, in milliseconds, before the `onLongPress` callback is invoked. Default is 600.
811
812### `RectButton`
813
814Use `RectButton` for rectangular elements or content blocks that are pressable, such as table rows or buttons with text and icons. It provides platform-specific interactions: a rectangular ripple on Android, background highlighting on iOS, and similar effects on older Android versions. In addition to `BaseButton` properties, it includes:
815
816#### Properties specific to `RectButton`:
817
818- **underlayColor**: The background color dimmed when the button is active.
819
820- **activeOpacity** (**iOS only**): The opacity applied to the underlay during the active state.
821
822### `BorderlessButton`
823
824Use `BorderlessButton` for simple icon-only or text-only buttons. Interaction varies by platform: a borderless ripple on Android and background dimming on iOS, similar to `TouchableOpacity`. In addition to `BaseButton` properties, it includes:
825
826#### Properties specific to `BorderlessButton`:
827
828- **borderless** (**Android only**): Set to `false` if the ripple should be confined within view bounds.
829
830- **activeOpacity** (**iOS only**): The opacity applied during the active state.
831
832### Design Patterns
833
834These components are not designed to behave identically across platforms but rather to handle similar behaviors on iOS and Android, considering their design concepts. For platform-specific design patterns, refer to official Apple documentation and Material.io guidelines.
835
836The library supports using native components with native feedback in appropriate situations. If a custom design approach is unnecessary, `RectButton` and `BorderlessButton` are sufficient. Otherwise, rely on `BaseButton`, which can be customized for specific needs.
837
838#### Common Use Cases
839
840- **Lists and Action Buttons**: Use `RectButton` for list items or action buttons that appear as separate UI blocks. It changes opacity on click and supports a ripple effect on Android. Emphasis is achieved through fill color or transparency, with outlined buttons used for medium emphasis.
841
842- **Icon or Text Only Buttons**: Use `BorderlessButton` for simple icon-only or text-only buttons. Interaction varies by platform: borderless ripple on Android and dimming on iOS. Suitable for non-crucial actions.
843
844#### `PureNativeButton`
845
846For more complex button implementations, use `PureNativeButton` to access the native component. It is generally not recommended but can be useful when wrapping with Animated or Reanimated:
847
848```tsx
849import {
850 createNativeWrapper,
851 PureNativeButton,
852} from "react-native-gesture-handler"
853import Animated from "react-native-reanimated"
854
855const { event, Value, createAnimatedComponent } = Animated
856
857const AnimatedRawButton = createNativeWrapper(
858 createAnimatedComponent(PureNativeButton),
859 {
860 shouldCancelWhenOutside: false,
861 shouldActivateOnStart: false,
862 }
863)
864
865export default class App extends React.Component {
866 constructor(props) {
867 super(props)
868 const state = new Value()
869 this._onGestureEvent = event([
870 {
871 nativeEvent: { state },
872 },
873 ])
874 }
875
876 render() {
877 return <AnimatedRawButton onHandlerStateChange={this._onGestureEvent} />
878 }
879}
880```
881
882## Gesture states & events
883
884Each gesture can be conceptualized as a "state machine." At any given moment, each handler instance is assigned a state that may change due to new touch events or specific conditions imposed by the touch system.
885
886A gesture can exist in one of six possible states:
887
888- **UNDETERMINED**
889
890 - This is the initial and default state for every gesture recognizer. After recognizing a gesture, it reverts to this state.
891
892- **FAILED**
893
894 - Occurs when a gesture recognizer receives touches but fails to recognize them due to certain conditions (e.g., exceeding `maxDist`). The state resets to `UNDETERMINED` after failing.
895
896- **BEGAN**
897
898 - Indicates that the gesture recognizer has started receiving touch input but hasn't gathered enough data to either fail or activate fully.
899
900- **CANCELLED**
901
902 - Triggered when a continuous gesture is interrupted by new touches or commands from the touch system controller. The state remains `CANCELLED` until it resets to `UNDETERMINED`.
903
904- **ACTIVE**
905
906 - Represents a recognized gesture that continues until completion (e.g., finger lift) or cancellation. Normally transitions to `END`, but if cancelled, moves to `CANCELLED`.
907
908- **END**
909 - Signifies the end of touch input for a gesture. The state becomes `END` and remains so until it resets to `UNDETERMINED`.
910
911### State Flows
912
913Typically, a gesture progresses from an initial touch event through recognition and acknowledgment of its conclusion before resetting to the initial state.
914
915### Events
916
917RNGH2 defines three types of events: `StateChangeEvent`, `GestureEvent`, and `PointerEvent`.
918
919- **`StateChangeEvent`**: Triggered whenever a gesture transitions between states, carrying both current and previous state information.
920
921- **`GestureEvent`**: Occurs with each update to a gesture, including the current state.
922
923- **`PointerEvent`**: Provides raw touch event data (e.g., screen touches or finger movements) handled internally before reaching callbacks.
924
925#### Event Callbacks
926
927- **`onBegin`**
928
929 - Invoked when transitioning to the `BEGAN` state.
930
931- **`onStart`**
932
933 - Triggered upon entering the `ACTIVE` state.
934
935- **`onEnd`**
936
937 - Called during transitions from `ACTIVE` to `END`, `FAILED`, or `CANCELLED`. The `success` argument is `true` for `END`, otherwise `false`.
938
939- **`onFinalize`**
940
941 - Executed when transitioning to `END`, `FAILED`, or `CANCELLED`. Similar to `onEnd`, with the `success` parameter indicating a successful transition. Follows `onEnd` if moving from `ACTIVE`.
942
943- **`onUpdate`**
944
945 - Triggered during updates while in the `ACTIVE` state.
946
947- **`onPointerDown`**
948
949 - Occurs when new pointers touch the screen, potentially involving multiple pointers due to event batching.
950
951- **`onPointerMove`**
952
953 - Activated when pointers move on the screen, possibly including data for multiple pointers.
954
955- **`onPointerUp`**
956
957 - Triggered when pointers are lifted from the screen, with potential information about multiple pointers.
958
959- **`onPointerCancelled`**
960 - Called when no further pointer information is available due to gesture completion or interruption. May involve multiple pointers due to event batching.
961
962## Handler State
963
964Gesture handlers are conceptualized as "state machines," where each instance maintains an assigned state that can change due to new touch events or be altered by the touch system under specific conditions. There are six possible states for a gesture handler:
965
966- **UNDETERMINED**
967- **FAILED**
968- **BEGAN**
969- **CANCELLED**
970- **ACTIVE**
971- **END**
972
973Each of these states is detailed below.
974
975### Accessing State
976
977To monitor changes in a handler's state, use the `onHandlerStateChange` callback along with the destructured `nativeEvent` argument. The `state` attribute within `nativeEvent` can be compared to constants from the `State` object (as demonstrated in the example).
978
979```typescript
980import { State, LongPressGestureHandler } from 'react-native-gesture-handler';
981
982class Demo extends Component {
983 _handleStateChange = ({ nativeEvent }) => {
984 if (nativeEvent.state === State.ACTIVE) {
985 Alert.alert('Longpress');
986 }
987 };
988
989 render() {
990 return (
991 <LongPressGestureHandler onHandlerStateChange={this._handleStateChange}>
992 <Text style={styles.buttonText}>Longpress me</Text>
993 </LongPressGestureHandler>
994 );
995 }
996}
997```
998
999### State Flows
1000
1001The typical state flow for a gesture handler involves recognizing an initial touch event, acknowledging its conclusion, and resetting to the initial state. This sequence is represented as:
1002
1003`UNDETERMINED` -> `BEGAN` -----> `ACTIVE` -----> `END` -> `UNDETERMINED`
1004
1005A different flow occurs when touches lead to recognition failure:
1006
1007`UNDETERMINED` -> `BEGAN` -----> `FAILED` -> `UNDETERMINED`
1008
1009If a gesture is recognized but interrupted by the touch system, it results in cancellation:
1010
1011`UNDETERMINED` -> `BEGAN` -----> `ACTIVE` -----> `CANCELLED` -> `UNDETERMINED`
1012
1013### States Description
1014
1015#### UNDETERMINED
1016
1017The initial state of each handler, returning to this state after gesture recognition is complete.
1018
1019#### FAILED
1020
1021Occurs when touches are received but not recognized due to constraints like exceeding a defined `maxDist`. The state resets to `UNDETERMINED` afterward.
1022
1023#### BEGAN
1024
1025Indicates the start of touch stream reception without sufficient data for failure or activation.
1026
1027#### CANCELLED
1028
1029Triggered by new touches or commands from the touch system, leading to gesture recognition cancellation. The state transitions back to `UNDETERMINED`.
1030
1031#### ACTIVE
1032
1033The handler recognizes a gesture and remains in this state until the gesture concludes (e.g., finger lift) or is cancelled. Normally, it progresses to `END`, but if cancelled by the touch system, it becomes `CANCELLED`. Further details on discrete and continuous handlers can provide insights into how long a handler stays `ACTIVE`.
1034
1035#### END
1036
1037Signifies the end of a gesture with touches indicating completion. The state transitions to `UNDETERMINED` after resetting.
1038
1039## Legacy Gesture Handlers
1040
1041### Overview
1042
1043The legacy gesture handler API is scheduled for removal in upcoming versions of Gesture Handler. Users are encouraged to transition to the new gestures API. For detailed migration instructions, refer to the provided upgrading guide.
1044
1045### Cross-Handler Interactions
1046
1047The previous cross-handler interaction capabilities will be deprecated in future releases. Transitioning to the updated gestures API is recommended. Consult the upgrading guide for further details.
1048
1049### Common Handler Properties
1050
1051Properties common across handlers in the old API are slated for removal. Users should adopt the new gestures API and refer to the upgrading guide for assistance.
1052
1053### Specific Gesture Handlers
1054
1055#### Pan
1056
1057The pan gesture handler from the legacy API will be deprecated. Transitioning to the gestures API is advised. See the upgrading guide for more information.
1058
1059#### Tap
1060
1061The tap gesture handler in the old API will no longer be supported. Users should migrate to the new gestures API. Refer to the upgrading guide for guidance.
1062
1063#### Long Press
1064
1065Long press functionality from the legacy API will be removed. Transitioning to the gestures API is recommended. Consult the upgrading guide for more details.
1066
1067#### Rotation
1068
1069The rotation gesture handler in the old API will be deprecated. Migrating to the gestures API is advised. See the upgrading guide for further information.
1070
1071#### Fling
1072
1073Fling gesture handling from the legacy API will be removed. Users should transition to the new gestures API. Refer to the upgrading guide for assistance.
1074
1075#### Pinch
1076
1077The pinch gesture handler in the old API will no longer be supported. Transitioning to the gestures API is recommended. Consult the upgrading guide for more details.
1078
1079#### Force Touch
1080
1081Force touch functionality from the legacy API will be deprecated. Migrating to the gestures API is advised. See the upgrading guide for further information.
1082
1083### NativeView
1084
1085The `NativeView` component in the old API will be removed. Users should adopt the new gestures API and refer to the upgrading guide for assistance.
1086
1087### createNativeWrapper()
1088
1089The `createNativeWrapper()` function from the legacy API will no longer be supported. Transitioning to the gestures API is recommended. Consult the upgrading guide for more details.
1090
1091## Testing with Jest
1092
1093### Mocking Native Modules
1094
1095To load mocks provided by RNGH, add the following to your Jest configuration in `package.json`:
1096
1097```json
1098"setupFiles": ["./node_modules/react-native-gesture-handler/jestSetup.js"]
1099```
1100
1101Example configuration:
1102
1103```json
1104"jest": {
1105 "preset": "react-native",
1106 "setupFiles": ["./node_modules/react-native-gesture-handler/jestSetup.js"]
1107}
1108```
1109
1110### Testing Gestures and Gesture Handlers' Callbacks
1111
1112RNGH offers an API for triggering selected handlers:
1113
1114- `fireGestureHandler(gestureOrHandler, eventList)`
1115- `getByGestureTestId(testID)`
1116
1117#### fireGestureHandler(gestureOrHandler, eventList)
1118
1119This function simulates a sequence of events (starting with the `BEGIN` state and ending with one of `END`, `FAIL`, or `CANCEL`) that call appropriate callbacks associated with a specified gesture handler.
1120
1121##### Arguments
1122
1123###### `gestureOrHandler`
1124
1125Represents either:
1126
11271. A gesture handler component found using Jest queries, such as `getByTestId`.
11281. A gesture identified by `getByGestureTestId()`.
1129
1130###### `eventList`
1131
1132The event data passed to the relevant callback. RNGH automatically fills in missing data according to these rules:
1133
11341. The `oldState` is derived from the state of the previous event; for `BEGIN` events, it uses an `UNDETERMINED` value.
11351. Events following the first `ACTIVE` state can omit the `state` field.
11361. Handler-specific data (e.g., `numberOfTouches`, `x`) are filled with default values if missing.
11371. Missing `BEGIN` and `END` events are added, using data from the first and last provided event, respectively.
11381. If the initial event lacks a `state` field, it defaults to the `ACTIVE` state.
1139
1140Examples:
1141
1142```typescript
1143const oldStateFilled = [
1144 { state: State.BEGAN },
1145 { state: State.ACTIVE },
1146 { state: State.END },
1147] // Three events with specified states are fired.
1148
1149const implicitActiveState = [
1150 { state: State.BEGAN },
1151 { state: State.ACTIVE },
1152 { x: 5 },
1153 { state: State.END },
1154] // Four events, including two ACTIVE events (the second one has overridden additional data).
1155
1156const implicitBegin = [
1157 { x: 1, y: 11 },
1158 { x: 2, y: 12, state: State.FAILED },
1159] // Three events, including an implicit BEGAN event, one ACTIVE event, and a FAILED event with additional data.
1160
1161const implicitBeginAndEnd = [
1162 { x: 5, y: 15 },
1163 { x: 6, y: 16 },
1164 { x: 7, y: 17 },
1165] // Five events, including three ACTIVE events and implicit BEGAN and END events. The BEGAN event uses the first event's additional data, while the END event uses the last event's.
1166
1167const allImplicits = [] // Three events, one BEGIN, one ACTIVE, and one END with default values.
1168```
1169
1170##### Example
1171
1172Extracted from RNGH tests; refer to `Events.test.tsx` for full implementation:
1173
1174```typescript
1175it('sends events with additional data to handlers', () => {
1176 const panHandlers = mockedEventHandlers();
1177 render(<SingleHandler handlers={panHandlers} treatStartAsUpdate />);
1178 fireGestureHandler<PanGesture>(getByGestureTestId('pan'), [
1179 { state: State.BEGAN, translationX: 0 },
1180 { state: State.ACTIVE, translationX: 10 },
1181 { translationX: 20 },
1182 { translationX: 20 },
1183 { state: State.END, translationX: 30 },
1184 ]);
1185
1186 expect(panHandlers.active).toHaveBeenCalledTimes(3);
1187 expect(panHandlers.active).toHaveBeenLastCalledWith(
1188 expect.objectContaining({ translationX: 20 })
1189 );
1190});
1191```
1192
1193### getByGestureTestId(testID)
1194
1195Returns an opaque data type associated with a gesture, identified via the `testID` attribute in rendered components (see `withTestID` method).
1196
1197#### Arguments
1198
1199##### `testID`
1200
1201A string that uniquely identifies the gesture.
1202
1203#### Notes
1204
1205The `testID` must be unique among components rendered in the test.
1206
1207#### Example
1208
1209Refer to the example provided for `fireGestureHandler`.
1210
1211## About Gesture Handlers
1212
1213> **Warning:** The old API will be removed in a future version of Gesture Handler. Please migrate to the gestures API instead. Refer to our upgrading guide for more information.
1214
1215### Overview
1216
1217Gesture handlers are fundamental components of this library, representing elements of the native touch system that can be instantiated and controlled from JavaScript using React's Component interface. Each handler type is designed to recognize specific gestures (such as pan or pinch) and provides gesture-specific data through events (like translation or scale).
1218
1219Handlers process the touch stream synchronously on the UI thread, ensuring smooth interactions even if the JavaScript thread is blocked.
1220
1221Each handler functions as an isolated state machine, transitioning between states based on input from the touch stream. When a gesture begins, handlers potentially interested in recognizing it are selected based on the initial finger position. All subsequent touch events (touch down, move, up, or when other fingers are placed or lifted) are delivered to these initially selected handlers. Once one gesture becomes active, it cancels all others (see "Cross handler interactions" for more details).
1222
1223Gesture handler components do not create native views in the view hierarchy; instead, they exist within the library's registry and connect to native views. When using any gesture handler component, ensure a native view is rendered as its child since these handlers lack corresponding views in the hierarchy.
1224
1225### Available Gesture Handlers
1226
1227The library currently supports the following gestures, with detailed documentation available for each:
1228
1229- `PanGestureHandler`
1230- `TapGestureHandler`
1231- `LongPressGestureHandler`
1232- `RotationGestureHandler`
1233- `FlingGestureHandler`
1234- `PinchGestureHandler`
1235- `ForceTouchGestureHandler`
1236
1237### Discrete vs Continuous Gestures
1238
1239Gestures are categorized as either discrete or continuous:
1240
1241- **Continuous Gesture Handlers**: Remain active for extended periods, generating a stream of gesture events until the gesture concludes. For example, `PanGestureHandler` provides updates on translation and other properties while active.
1242
1243- **Discrete Gesture Handlers**: Activate briefly and end immediately. An example is `LongPressGestureHandler`, which detects if a finger remains placed for a sufficient duration without tracking movements (handled by `PanGestureHandler`).
1244
1245Note: The `onGestureEvent` callback is only applicable to continuous gesture handlers and should not be used with discrete handlers like `TapGestureHandler`.
1246
1247### Nesting Handlers
1248
1249Handler components can be nested, but it's recommended that the innermost handler renders a native view component. Some limitations apply when using the `useNativeDriver` flag. Here’s an example of nested handlers:
1250
1251```typescript
1252class Multitap extends Component {
1253 render() {
1254 return (
1255 <LongPressGestureHandler
1256 onHandlerStateChange={this._onLongpress}
1257 minDurationMs={800}>
1258 <TapGestureHandler
1259 onHandlerStateChange={this._onSingleTap}
1260 waitFor={this.doubleTapRef}>
1261 <TapGestureHandler
1262 ref={this.doubleTapRef}
1263 onHandlerStateChange={this._onDoubleTap}
1264 numberOfTaps={2}>
1265 <View style={styles.box} />
1266 </TapGestureHandler>
1267 </TapGestureHandler>
1268 </LongPressGestureHandler>
1269 );
1270 }
1271}
1272```
1273
1274### Using Native Components
1275
1276The gesture handler library provides components typically available in React Native, wrapped in `NativeViewGestureHandler`. These include:
1277
1278- `ScrollView`
1279- `FlatList`
1280- `Switch`
1281- `TextInput`
1282- `DrawerLayoutAndroid` (**Android only**)
1283
1284For using other handlers or buttons within a `ScrollView`, utilize the `waitFor` property to define interactions between a handler and `ScrollView`.
1285
1286### Events with `useNativeDriver`
1287
1288Since gesture handlers hook into their child views rather than creating native views, directly nesting two gesture handlers with `Animated.event` is not supported. To address this limitation, place an `<Animated.View>` component between the handlers.
1289
1290Instead of:
1291
1292```typescript
1293const PanAndRotate = () => (
1294 <PanGestureHandler onGestureEvent={Animated.event({ ... }, { useNativeDriver: true })}>
1295 <RotationGestureHandler onGestureEvent={Animated.event({ ... }, { useNativeDriver: true })}>
1296 <Animated.View style={animatedStyles}/>
1297 </RotationGestureHandler>
1298 </PanGestureHandler>
1299);
1300```
1301
1302Use:
1303
1304```typescript
1305const PanAndRotate = () => (
1306 <PanGestureHandler onGestureEvent={Animated.event({ ... }, { useNativeDriver: true })}>
1307 <Animated.View>
1308 <RotationGestureHandler onGestureEvent={Animated.event({ ... }, { useNativeDriver: true })}>
1309 <Animated.View style={animatedStyles}/>
1310 </RotationGestureHandler>
1311 </Animated.View>
1312 </PanGestureHandler>
1313);
1314```
1315
1316Additionally, when using the `useNativeDriver` flag with an `Animated.event`, ensure the child component is wrapped by an `Animated.API` (e.g., `<Animated.View>`) instead of a regular `<View>`:
1317
1318```typescript
1319class Draggable extends Component {
1320 render() {
1321 return (
1322 <PanGestureHandler onGestureEvent={Animated.event({ ... }, { useNativeDriver: true })}>
1323 <Animated.View style={animatedStyles} /> {/* <-- NEEDS TO BE Animated.View */}
1324 </PanGestureHandler>
1325 );
1326 }
1327}
1328```
1329
1330## Custom Swipeable Component with Scroll Functionality
1331
1332When developing a custom swipeable component, you may encounter issues where scrolling does not function as expected. To address this, it is recommended to set the `touchAction` property to `"pan-y"` within your gesture detector configuration.
1333
1334Here's how you can implement this:
1335
1336```typescript
1337<GestureDetector gesture={...} touchAction="pan-y">
1338 ...
1339</GestureDetector>
1340```
1341
1342By setting `touchAction` to `"pan-y"`, you allow vertical panning, which helps maintain scroll functionality in your custom swipeable component.
1343
1344## Cross handler interactions
1345
1346**Warning:** The old API will be removed in future versions of Gesture Handler. Please migrate to the gestures API instead. Refer to our upgrading guide for more information.
1347
1348Gesture handlers can "communicate" with each other to support complex gestures and control how they activate under certain scenarios. There are two methods described below for achieving this communication. In both cases, it is necessary to provide a reference of one handler as a property to the other. Gesture handlers rely on ref objects created using `React.createRef()` introduced in React 16.3.
1349
1350### Simultaneous Recognition
1351
1352By default, only one gesture handler can be in the `ACTIVE` state at any given time. When a gesture handler recognizes a gesture, it cancels all other handlers that are in the `BEGAN` state and prevents any new handlers from receiving a stream of touch events as long as it remains `ACTIVE`.
1353
1354This behavior can be modified using the `simultaneousHandlers` property (available for all types of handlers). This property accepts a ref or an array of refs to other handlers. Handlers connected in this way will be allowed to remain in the `ACTIVE` state simultaneously.
1355
1356#### Use Cases
1357
1358Simultaneous recognition is necessary when implementing a photo preview component that supports zooming (scaling), rotating, and panning while zoomed in. In such cases, you would use a `PinchGestureHandler`, `RotationGestureHandler`, and `PanGestureHandler` to recognize gestures at the same time.
1359
1360#### Example
1361
1362See the "Scale, rotate & tilt" example from the GestureHandler Example App or view it directly on your phone by visiting our expo demo.
1363
1364```typescript
1365class PinchableBox extends React.Component {
1366 // ...take a look at full implementation in an Example app
1367 render() {
1368 const imagePinch = React.createRef();
1369 const imageRotation = React.createRef();
1370 return (
1371 <RotationGestureHandler
1372 ref={imageRotation}
1373 simultaneousHandlers={imagePinch}
1374 onGestureEvent={this._onRotateGestureEvent}
1375 onHandlerStateChange={this._onRotateHandlerStateChange}>
1376 <Animated.View>
1377 <PinchGestureHandler
1378 ref={imagePinch}
1379 simultaneousHandlers={imageRotation}
1380 onGestureEvent={this._onPinchGestureEvent}
1381 onHandlerStateChange={this._onPinchHandlerStateChange}>
1382 <Animated.View style={styles.container} collapsable={false}>
1383 <Animated.Image
1384 style={[
1385 styles.pinchableImage,
1386 {
1387 /* events-related transformations */
1388 },
1389 ]}
1390 />
1391 </Animated.View>
1392 </PinchGestureHandler>
1393 </Animated.View>
1394 </RotationGestureHandler>
1395 );
1396 }
1397}
1398```
1399
1400### Awaiting Other Handlers
1401
1402#### Use Cases
1403
1404A good example where awaiting is necessary is when you want to have single and double tap handlers registered for one view (e.g., a button). In such cases, the single tap handler should await the double tap. Otherwise, if you try to perform a double tap, the single tap handler will fire after the first hit on the button, consequently cancelling the double tap handler.
1405
1406#### Example
1407
1408See the "Multitap" example from GestureHandler Example App or view it directly on your phone by visiting our expo demo.
1409
1410```typescript
1411const doubleTap = React.createRef();
1412const PressBox = () => (
1413 <TapGestureHandler
1414 onHandlerStateChange={({ nativeEvent }) =>
1415 nativeEvent.state === State.ACTIVE && Alert.alert('Single tap!')
1416 }
1417 waitFor={doubleTap}>
1418 <TapGestureHandler
1419 ref={doubleTap}
1420 onHandlerStateChange={({ nativeEvent }) =>
1421 nativeEvent.state === State.ACTIVE && Alert.alert("You're so fast")
1422 }
1423 numberOfTaps={2}>
1424 <View style={styles.box} />
1425 </TapGestureHandler>
1426 </TapGestureHandler>
1427);
1428```
1429
1430## Fling gesture
1431
1432A discrete gesture activated by sufficiently long and fast movement. The gesture becomes ACTIVE when the movement meets these criteria, transitioning to END upon finger release. If the finger lifts before activation, recognition fails.
1433
1434### Example
1435
1436```typescript
1437import { StyleSheet } from 'react-native';
1438import {
1439 Gesture,
1440 GestureDetector,
1441 Directions,
1442} from 'react-native-gesture-handler';
1443import Animated, {
1444 useSharedValue,
1445 useAnimatedStyle,
1446 withTiming,
1447} from 'react-native-reanimated';
1448
1449export default function App() {
1450 const position = useSharedValue(0);
1451 const flingGesture = Gesture.Fling()
1452 .direction(Directions.RIGHT)
1453 .onStart((e) => {
1454 position.value = withTiming(position.value + 10, { duration: 100 });
1455 });
1456
1457 const animatedStyle = useAnimatedStyle(() => ({
1458 transform: [{ translateX: position.value }],
1459 }));
1460
1461 return (
1462 <GestureDetector gesture={flingGesture}>
1463 <Animated.View style={[styles.box, animatedStyle]} />
1464 </GestureDetector>
1465 );
1466}
1467
1468const styles = StyleSheet.create({
1469 box: {
1470 height: 120,
1471 width: 120,
1472 backgroundColor: '#b58df1',
1473 borderRadius: 20,
1474 marginBottom: 30,
1475 },
1476});
1477```
1478
1479### Configuration
1480
1481#### Properties Specific to `FlingGesture`:
1482
1483|Property|Description|||
1484|-|-|-|-|
1485|`direction(value: Directions)`|Specifies allowed movement directions. Use constants from the `Directions` object, combining multiple directions with \`|`. Example: `fling.direction(Directions.RIGHT|Directions.LEFT);`or`fling.direction(Directions.DOWN);\`|
1486|`numberOfPointers(value: number)`|Sets the exact number of pointers required for gesture recognition.|||
1487|`mouseButton(value: MouseButton)` (Web & Android only)|Chooses which mouse button to respond to, using predefined fields in `MouseButton`: `LEFT`, `RIGHT`, `MIDDLE`, `BUTTON_4`, `BUTTON_5`, `ALL`. Combine with \`|`operator; default is`LEFT\`.||
1488
1489#### Properties Common to All Gestures:
1490
1491|Property|Description|
1492|-|-|
1493|`enabled(value: boolean)`|Determines if the handler analyzes touch events. Default is `true`. Disabling during recognition changes state to `FAILED` or `CANCELLED`.|
1494|`shouldCancelWhenOutside(value: boolean)`|Cancels/fails recognition when a finger leaves the view area. Defaults vary by gesture type; most are `false`, except for `LongPressGesture` and `TapGesture` which default to `true`.|
1495|`hitSlop(settings)`|Controls the active area for gesture recognition, reducing or expanding bounds as specified. Supports negative numbers, objects with specific side reductions, and `width`/`height` attributes.|
1496|`withRef(ref)`|Sets a ref for interoperability with older APIs.|
1497|`withTestId(testID)`|Assigns a `testID` for querying in tests.|
1498|`cancelsTouchesInView(value)` (**iOS only**)|When `true`, cancels touches for native UI components when active. Default is `true`.|
1499|`runOnJS(value: boolean)`|Determines if callbacks run on the JS thread (`true`) or UI thread (`false`). Defaults to `false` with `react-native-reanimated`.|
1500|`simultaneousWithExternalGesture(otherGesture1, otherGesture2, ...)`|Marks gestures for simultaneous recognition without composing them. Requires separate detectors.|
1501|`requireExternalGestureToFail(otherGesture1, otherGesture2, ...)`|Requires another gesture to fail before activation. Does not compose gestures; requires separate detectors.|
1502|`blocksExternalGesture(otherGesture1, otherGesture2, ...)`|Delays other gestures until this one fails or doesn't start. Marks relations without composing; requires separate detectors.|
1503
1504### Callbacks
1505
1506#### Common to All Gestures:
1507
1508|Callback|Description|
1509|-|-|
1510|`onBegin(callback)`|Called when the gesture handler starts receiving touches but hasn't yet recognized the gesture.|
1511|`onStart(callback)`|Triggered when the gesture is recognized and transitions to active state.|
1512|`onEnd(callback)`|Invoked when a recognized gesture finishes, only if previously active.|
1513|`onFinalize(callback)`|Called upon finalizing gesture handling—either recognition or failure.|
1514|`onTouchesDown(callback)`|Executed every time a finger touches the screen.|
1515|`onTouchesMove(callback)`|Triggered with each finger movement on the screen.|
1516|`onTouchesUp(callback)`|Invoked when a finger is lifted from the screen.|
1517|`onTouchesCancelled(callback)`|Called when a finger stops being tracked, such as gesture completion.|
1518
1519### Event Data
1520
1521#### Specific to `FlingGesture`:
1522
1523|Attribute|Description|
1524|-|-|
1525|`x`|X coordinate of the pointer relative to the attached view (in points).|
1526|`y`|Y coordinate of the pointer relative to the attached view (in points).|
1527|`absoluteX`|X coordinate of the pointer relative to the window, recommended for transformed views.|
1528|`absoluteY`|Y coordinate of the pointer relative to the window, recommended for transformed views.|
1529
1530#### Common to All Gestures:
1531
1532|Attribute|Description|
1533|-|-|
1534|`state`|Current handler state, expressed as constants from the `State` object.|
1535|`numberOfPointers`|Number of pointers currently on the screen.|
1536|`pointerType`|Type of pointer device, using `PointerType`: `TOUCH`, `STYLUS`, `MOUSE`, `KEY`, `OTHER`.|
1537
1538## Common handler properties
1539
1540**Warning:** The old API will be removed in future versions of Gesture Handler. Please migrate to the gestures API instead. Refer to our upgrading guide for more information.
1541
1542This page covers the common set of properties that all gesture handler components expose.
1543
1544### Units
1545
1546All handler component properties and event attributes representing onscreen dimensions are expressed in screen density-independent units known as "points." These units are commonly used in the React Native ecosystem (e.g., in the layout system). They do not map directly to physical pixels but correspond to iOS's points and Android's dp units.
1547
1548### Properties
1549
1550This section describes properties applicable to all gesture handler components:
1551
1552#### `enabled`
1553
1554- **Type:** Boolean
1555- **Description:** Indicates whether the handler should analyze a stream of touch events. When set to `false`, the handler's state will never become `ACTIVE`. If updated while recognizing a gesture, it changes to `FAILED` or `CANCELLED` based on its current state.
1556- **Default Value:** `true`
1557
1558#### `shouldCancelWhenOutside`
1559
1560- **Type:** Boolean
1561- **Description:** When `true`, the handler cancels or fails recognition if the finger leaves the connected view's area. The default value varies by handler type; most handlers default to `false`, except for `LongPressGestureHandler` and `TapGestureHandler`, which default to `true`.
1562
1563#### `cancelsTouchesInView` (**iOS only**)
1564
1565- **Type:** Boolean
1566- **Description:** When `true`, the handler cancels touches for native UI components (e.g., `UIButton`, `UISwitch`) it's attached to when active.
1567- **Default Value:** `true`
1568
1569#### `simultaneousHandlers`
1570
1571- **Type:** React ref object or array of refs
1572- **Description:** Allows activation even if other handlers provided by their refs are in an `ACTIVE` state. Prevents these handlers from cancelling the current handler upon activation. See cross-handler interaction for more details.
1573
1574#### `waitFor`
1575
1576- **Type:** React ref object or array of refs
1577- **Description:** The handler will not activate as long as handlers provided by their refs are in the `BEGAN` state. See cross-handler interaction for more details.
1578
1579#### `hitSlop`
1580
1581- **Description:** Controls the area within the connected view where gesture recognition can begin. A negative number reduces the view's bounds evenly on all sides. Alternatively, an object can specify reductions for each side (`left`, `right`, `top`, `bottom`) or use `horizontal`/`vertical`. The object may also include `width` and `height` attributes to restrict activation to edges.
1582- **Note:** Primarily designed to reduce the gesture activation area; supported values are non-positive (0 or lower) on all platforms except Android, where positive values expand beyond view bounds but not past parent view bounds. Use React Native's View hitSlop property for cross-platform support.
1583
1584#### `userSelect` (**Web only**)
1585
1586- **Type:** `"none" | "auto" | "text"`
1587- **Description:** Specifies the `userSelect` property applied to the underlying view.
1588- **Default Value:** `"none"`
1589
1590#### `activeCursor` (**Web only**)
1591
1592- **Type:** CSS cursor value (e.g., `"grab"`, `"zoom-in"`)
1593- **Description:** Specifies the cursor used when a gesture activates.
1594- **Default Value:** `"auto"`
1595
1596#### `onGestureEvent`
1597
1598- **Type:** Callback or `Animated.event`
1599- **Description:** Triggered for each touch event while the handler is in an ACTIVE state. The event payload varies by handler type, with common attributes documented below and specific ones on corresponding handler pages.
1600
1601#### `onHandlerStateChange`
1602
1603- **Type:** Callback or `Animated.event`
1604- **Description:** Triggered when the handler's state changes. Includes the same payload as `onGestureEvent` plus an `oldState` attribute representing the previous state before the change.
1605
1606### Event Data
1607
1608This section describes attributes of the event object provided to `onGestureEvent` and `onHandlerStateChange` callbacks:
1609
1610#### `state`
1611
1612- **Description:** Current state of the handler, expressed as one of the constants in the `State` object exported by the library. Refer to the handler state section for more details.
1613
1614#### `numberOfPointers`
1615
1616- **Description:** Represents the number of pointers (fingers) currently on the screen.
1617
1618## Hover gesture
1619
1620A continuous gesture designed to recognize hovering actions over a view. This can be triggered by moving a mouse or stylus above the view.
1621
1622On iOS, additional visual effects are configurable.
1623
1624### Reference
1625
1626```typescript
1627import { GestureDetector, Gesture } from 'react-native-gesture-handler';
1628
1629function App() {
1630 const hover = Gesture.Hover();
1631
1632 return (
1633 <GestureDetector gesture={hover}>
1634 <View />
1635 </GestureDetector>
1636 );
1637}
1638```
1639
1640### Remarks
1641
1642- The `Hover` gesture does not continue after a mouse click or stylus touch. For handling both scenarios, combine it with the `Pan` gesture.
1643
1644### Configuration
1645
1646#### Properties Specific to `HoverGesture` (iOS Only)
1647
1648##### `effect(effect: HoverEffect)`
1649
1650Defines the visual effect applied while hovering over the view. Possible values include:
1651
1652- `HoverEffect.None`
1653- `HoverEffect.Lift`
1654- `HoverEffect.Highlight`
1655
1656Defaults to `HoverEffect.None`.
1657
1658```typescript
1659import { HoverEffect } from "react-native-gesture-handler"
1660```
1661
1662#### Properties Common to All Gestures
1663
1664##### `enabled(value: boolean)`
1665
1666Determines if the handler analyzes touch events. When set to `false`, the handler's state will never be `ACTIVE`. If updated during gesture recognition, it transitions to `FAILED` or `CANCELLED`. Default is `true`.
1667
1668##### `shouldCancelWhenOutside(value: boolean)`
1669
1670If `true`, the handler cancels or fails when a finger leaves the view area. Defaults vary by handler type; most are `false`, except for `LongPressGesture` and `TapGesture`, which default to `true`.
1671
1672##### `hitSlop(settings)`
1673
1674Controls the gesture activation area within the view. Negative numbers reduce the bounds evenly on all sides. Alternatively, specify reductions per side (`left`, `right`, `top`, `bottom`) or use `horizontal`/`vertical`. You can also set `width` and `height` to restrict gestures to edges.
1675
1676**Note:** Primarily reduces activation area; supported for non-positive values (0 or lower). On Android, positive values are allowed but limited by parent view bounds. For cross-platform edge effects, use React Native's View hitSlop property.
1677
1678##### `withRef(ref)`
1679
1680Sets a ref to the gesture object for interoperability with older APIs.
1681
1682##### `withTestId(testID)`
1683
1684Assigns a `testID` to the gesture object for test querying.
1685
1686##### `cancelsTouchesInView(value)` (iOS Only)
1687
1688When `true`, cancels touches for native UI components (`UIButton`, `UISwitch`, etc.) when active. Default is `true`.
1689
1690##### `runOnJS(value: boolean)`
1691
1692If `react-native-reanimated` is installed, callbacks are workletized and run on the UI thread by default. Setting this to `true` runs all callbacks on the JS thread instead. Defaults to `false`.
1693
1694##### `simultaneousWithExternalGesture(otherGesture1, otherGesture2, ...)`
1695
1696Marks gestures for simultaneous recognition without composing them. Requires adding `otherGestures` to another detector.
1697
1698##### `requireExternalGestureToFail(otherGesture1, otherGesture2, ...)`
1699
1700Requires specified gestures to fail before this one can activate.
1701
1702##### `blocksExternalGesture(otherGesture1, otherGesture2, ...)`
1703
1704Prevents specified gestures from activating until this gesture fails or doesn't start. Requires adding `otherGestures` to another detector.
1705
1706**Note:** Marks relations without composing them; `GestureDetector` won't recognize `otherGestures`.
1707
1708##### `activeCursor(value)` (Web Only)
1709
1710Specifies the cursor style when the gesture activates, supporting all CSS cursor values (e.g., `"grab"`, `"zoom-in"`). Default is `"auto"`.
1711
1712### Callbacks
1713
1714#### Common to All Gestures
1715
1716##### `onBegin(callback)`
1717
1718Called when the handler starts receiving touches but hasn't yet recognized a gesture.
1719
1720##### `onStart(callback)`
1721
1722Triggered when the gesture is recognized and transitions to an active state.
1723
1724##### `onEnd(callback)`
1725
1726Invoked when a recognized gesture finishes, provided it was previously in an active state.
1727
1728##### `onFinalize(callback)`
1729
1730Called when the handler finalizes handling a gesture, whether recognized or failed.
1731
1732##### `onTouchesDown(callback)`
1733
1734Executed every time a finger touches the screen.
1735
1736##### `onTouchesMove(callback)`
1737
1738Triggered whenever a finger moves on the screen.
1739
1740##### `onTouchesUp(callback)`
1741
1742Invoked each time a finger is lifted from the screen.
1743
1744##### `onTouchesCancelled(callback)`
1745
1746Called when a finger stops being tracked, such as when a gesture finishes.
1747
1748#### Common to All Continuous Gestures
1749
1750##### `onUpdate(callback)`
1751
1752Executed every time an active gesture receives an update.
1753
1754##### `onChange(callback)`
1755
1756Triggered with updates during an active gesture, providing change information relative to the last event.
1757
1758### Event Data Specific to `HoverGesture`
1759
1760- **`x`**: X coordinate of the pointer relative to the view, in points.
1761- **`y`**: Y coordinate of the pointer relative to the view, in points.
1762- **`absoluteX`**: X coordinate of the pointer relative to the window, in points. Use this for transformed views.
1763- **`absoluteY`**: Y coordinate of the pointer relative to the window, in points. Use this for transformed views.
1764- **`stylusData`**: Contains additional stylus information:
1765 - `tiltX`: Angle between the Y-Z plane of the stylus and the screen (degrees).
1766 - `tiltY`: Angle between the X-Z plane of the stylus and the screen (degrees).
1767 - `altitudeAngle`: Angle between stylus axis and device screen's X-Y plane.
1768 - `azimuthAngle`: Angle between the Y-Z plane and the plane containing both the stylus axis and the Y axis.
1769 - `pressure`: Normalized pressure of the stylus.
1770
1771### Event Attributes Common to All Gestures
1772
1773- **`state`**: Current state of the handler, expressed as a constant from the `State` object.
1774- **`numberOfPointers`**: Number of pointers (fingers) on the screen.
1775- **`pointerType`**: Type of pointer device in use, represented by the `PointerType` enum:
1776 - `TOUCH`: Finger
1777 - `STYLUS`: Stylus or digital pen
1778 - `MOUSE`: Computer mouse
1779 - `KEY`: Keyboard
1780 - `OTHER`: Unknown device type
1781
1782## PanGestureHandler
1783
1784> **Warning:** The old API will be removed in a future version of Gesture Handler. Please migrate to the gestures API instead. Refer to our upgrading guide for more information.
1785
1786The `PanGestureHandler` is a continuous gesture handler designed to recognize and track panning (dragging) gestures. It activates when a finger touches the screen and moves beyond an initial distance.
1787
1788### Custom Activation Criteria
1789
1790The `PanGestureHandler` component offers several properties to customize activation criteria:
1791
1792- **Multiple Properties:** When multiple properties are set, all must be met for successful recognition, and at least one can be exceeded to fail recognition.
1793 - Example: Setting both `minDeltaX` and `minDeltaY` to 20 requires movement of 20 points in both axes. Conversely, setting `maxDeltaX`, `maxDeltaY` to 20, and `minDist` to 23 will cause failure if the finger moves 20 points along X-axis but not Y-axis.
1794
1795### Multi-Touch Pan Handling
1796
1797#### Platform Differences:
1798
1799- **iOS:** Treats multiple fingers as a single pointer at their center of mass.
1800- **Android:** Defaults to using the latest placed finger for translation properties, similar to native components like scroll views.
1801
1802#### Customization:
1803
1804- On Android, use `avgTouches` to switch to iOS-like behavior (center of mass).
1805
1806Note: Translation properties remain unaffected by additional fingers unless tracking the "center of mass" is required. Use relative or absolute positions (`x`, `y`, `absoluteX`, `absoluteY`) for such cases.
1807
1808### Properties
1809
1810Inherits from base handler class with specific properties:
1811
1812- **`minDist`:** Minimum distance to activate (in points).
1813- **`minPointers`:** Required number of fingers before activation.
1814- **`maxPointers`:** Maximum number of fingers allowed; exceeding this fails recognition.
1815- **`activeOffsetX/Y`:** Range along X or Y axis without activating the handler. Can be an array `[lower, upper]` or a single value `p`.
1816- **`failOffsetX/Y`:** Range beyond which gesture recognition fails if not yet activated.
1817- **Deprecated Methods:**
1818 - Use `failOffsetX={[-N, N]}` instead of `maxDeltaX={N}`.
1819 - Use `failOffsetY={[-N, N]}` instead of `maxDeltaY={N}`.
1820
1821### Event Data
1822
1823Includes attributes specific to `PanGestureHandler`:
1824
1825- **`translationX/Y`:** Accumulated translation along X or Y axis (in points).
1826- **`velocityX/Y`:** Current velocity along X or Y axis (points per second).
1827- **`x/y`:** Relative position of the pointer to the view.
1828- **`absoluteX/Y`:** Position relative to the window, recommended for transformed views.
1829
1830### Example
1831
1832```typescript
1833import React, { Component } from 'react';
1834import { Animated, Dimensions } from 'react-native';
1835import {
1836 GestureHandlerRootView,
1837 PanGestureHandler,
1838} from 'react-native-gesture-handler';
1839
1840const { width } = Dimensions.get('screen');
1841const circleRadius = 30;
1842
1843class Circle extends Component {
1844 _touchX = new Animated.Value(width / 2 - circleRadius);
1845
1846 _onPanGestureEvent = Animated.event([{ nativeEvent: { x: this._touchX } }], {
1847 useNativeDriver: true,
1848 });
1849
1850 render() {
1851 return (
1852 <GestureHandlerRootView>
1853 <PanGestureHandler onGestureEvent={this._onPanGestureEvent}>
1854 <Animated.View
1855 style={{
1856 height: 150,
1857 justifyContent: 'center',
1858 }}>
1859 <Animated.View
1860 style={[
1861 {
1862 backgroundColor: '#42a5f5',
1863 borderRadius: circleRadius,
1864 height: circleRadius * 2,
1865 width: circleRadius * 2,
1866 },
1867 {
1868 transform: [
1869 {
1870 translateX: Animated.add(
1871 this._touchX,
1872 new Animated.Value(-circleRadius)
1873 ),
1874 },
1875 ],
1876 },
1877 ]}
1878 />
1879 </Animated.View>
1880 </PanGestureHandler>
1881 </GestureHandlerRootView>
1882 );
1883 }
1884}
1885
1886export default function App() {
1887 return <Circle />;
1888}
1889```
1890
1891## TapGestureHandler
1892
1893**Warning:**\
1894The old API will be deprecated in future versions of Gesture Handler. It is recommended to migrate to the gestures API. Refer to our upgrading guide for more details.
1895
1896A discrete gesture handler that recognizes one or multiple taps.
1897
1898Tap gestures detect brief contact by one or more fingers on the screen, with minimal movement from their initial touch positions. You can configure the number of required taps and the allowed distance from the starting position. For instance, tap gesture recognizers can be set up to detect single, double, or triple taps.
1899
1900For a handler to activate, specific gesture requirements such as `minPointers`, `numberOfTaps`, `maxDist`, `maxDurationMs`, and `maxDelayMs` must be satisfied. Once activated, the handler will immediately END.
1901
1902### Properties
1903
1904In addition to properties inherited from the base handler class, the `TapGestureHandler` component has specific properties:
1905
1906#### `minPointers`
1907
1908The minimum number of pointers (fingers) required before activation. This should be a positive integer with a default value of 1.
1909
1910#### `maxDurationMs`
1911
1912Defines the maximum time in milliseconds for how quickly a finger must be released after touching. The default is set to 500 ms.
1913
1914#### `maxDelayMs`
1915
1916Specifies the maximum allowable time in milliseconds between taps when multiple taps are required. The default is 500 ms.
1917
1918#### `numberOfTaps`
1919
1920The number of tap gestures needed to activate the handler, with a default value of 1.
1921
1922#### `maxDeltaX`
1923
1924Defines the maximum distance in points that a finger can travel along the X-axis during a tap gesture. If exceeded before activation, the gesture will not be recognized.
1925
1926#### `maxDeltaY`
1927
1928Specifies the maximum distance in points for movement along the Y-axis during a tap gesture. Exceeding this distance before activation results in failure to recognize the gesture.
1929
1930#### `maxDist`
1931
1932The maximum allowable distance in points that a finger can travel during a tap gesture. If exceeded, the handler will not recognize the gesture.
1933
1934### Event Data
1935
1936In addition to event attributes from the base handler class, the `TapGestureHandler` component has specific gesture event attributes:
1937
1938#### `x`
1939
1940X coordinate of the current pointer position (finger or leading pointer) relative to the view attached to the handler, expressed in points.
1941
1942#### `y`
1943
1944Y coordinate of the current pointer position (finger or leading pointer) relative to the view attached to the handler, expressed in points.
1945
1946#### `absoluteX`
1947
1948X coordinate of the current pointer position (finger or leading pointer) relative to the window. Use `absoluteX` instead of `x` when the view can be transformed due to gestures.
1949
1950#### `absoluteY`
1951
1952Y coordinate of the current pointer position (finger or leading pointer) relative to the window. Use `absoluteY` instead of `y` in cases where the view attached to the handler may transform as a result of gestures.
1953
1954### Example
1955
1956Refer to the multitap example from the GestureHandler Example App for implementation details.
1957
1958```typescript
1959export class PressBox extends Component {
1960 doubleTapRef = React.createRef();
1961
1962 render() {
1963 return (
1964 <TapGestureHandler
1965 onHandlerStateChange={this._onSingleTap}
1966 waitFor={this.doubleTapRef}>
1967 <TapGestureHandler ref={this.doubleTapRef} numberOfTaps={2}>
1968 <View style={styles.box} />
1969 </TapGestureHandler>
1970 </TapGestureHandler>
1971 );
1972 }
1973}
1974```
1975
1976## LongPressGestureHandler
1977
1978> **Warning:**\
1979> The old API will be deprecated in future versions of Gesture Handler. It is recommended to migrate to the gestures API. Refer to our upgrading guide for more information.
1980
1981The `LongPressGestureHandler` is a discrete gesture handler that activates when a view is pressed for a sufficient duration. Once the finger is released, the handler's state transitions to END immediately. The handler will not recognize a touch event if the finger is lifted before reaching the minimum required time or if it moves beyond an allowable distance.
1982
1983This handler utilizes `UILongPressGestureRecognizer` on iOS and `LongPressGestureHandler` on Android.
1984
1985### Properties
1986
1987The properties specific to the `LongPressGestureHandler` component are listed below. For additional inherited properties, refer to the base handler class documentation:
1988
1989#### `minDurationMs`
1990
1991- **Description:** Minimum duration in milliseconds that a finger must remain pressed on the view.
1992- **Default Value:** 500 ms.
1993
1994#### `maxDist`
1995
1996- **Description:** Maximum allowable distance in points that defines how far the finger can travel during a long press gesture. If exceeded before activation, the gesture is not recognized.
1997- **Default Value:** 10 points.
1998
1999### Event Data
2000
2001The event attributes specific to the `LongPressGestureHandler` component are detailed below. For more attributes from the base handler class, refer to its documentation:
2002
2003#### `x`
2004
2005- **Description:** X coordinate in points of the current pointer position (finger or leading pointer) relative to the view attached to the handler.
2006
2007#### `y`
2008
2009- **Description:** Y coordinate in points of the current pointer position (finger or leading pointer) relative to the view attached to the handler.
2010
2011#### `absoluteX`
2012
2013- **Description:** X coordinate in points of the current pointer position (finger or leading pointer) relative to the window. Use `absoluteX` instead of `x` if the view can be transformed due to gestures.
2014
2015#### `absoluteY`
2016
2017- **Description:** Y coordinate in points of the current pointer position (finger or leading pointer) relative to the window. Use `absoluteY` instead of `y` if the view can be transformed due to gestures.
2018
2019#### `duration`
2020
2021- **Description:** Duration of the long press gesture, measured from the start of the event, expressed in milliseconds.
2022
2023### Example
2024
2025Below is an example demonstrating how to use the `LongPressGestureHandler`:
2026
2027```typescript
2028const LongPressButton = () => (
2029 <LongPressGestureHandler
2030 onHandlerStateChange={({ nativeEvent }) => {
2031 if (nativeEvent.state === State.ACTIVE) {
2032 Alert.alert("I'm being pressed for so long");
2033 }
2034 }}
2035 minDurationMs={800}>
2036 <View style={styles.box} />
2037 </LongPressGestureHandler>
2038);
2039```
2040
2041This example sets up a button that triggers an alert when held down for more than 800 milliseconds.
2042
2043## Custom swipeable components inside ScrollView (web)
2044
2045When developing custom swipeable components within a `ScrollView` on the web, you might opt for more control over their behavior by creating your own version instead of using pre-built solutions like ReanimatedSwipeable. However, one common issue encountered is that scrolling functionality may not work as expected after implementing a custom swipeable component.
2046
2047To address this problem, consider setting the `touchAction` property to `"pan-y"`. This adjustment can help ensure that vertical panning and scrolling are handled correctly within your component.
2048
2049Here's an example of how you might implement this in TypeScript:
2050
2051```typescript
2052import React from 'react';
2053import { View } from 'react-native';
2054
2055const CustomSwipeableComponent: React.FC = () => {
2056 return (
2057 <View style={{ touchAction: 'pan-y' }}>
2058 {/* Your swipeable component implementation */}
2059 </View>
2060 );
2061};
2062
2063export default CustomSwipeableComponent;
2064```
2065
2066By setting `touchAction` to `"pan-y"`, you allow the browser to handle vertical panning, which can resolve issues with scrolling when using custom swipeable components inside a `ScrollView`.
2067
2068## Migrating off RNGHEnabledRootView
2069
2070### Update `MainActivity.java`
2071
2072Modify your `MainActivity.java` file (or wherever an instance of `ReactActivityDelegate` is created) to ensure that it no longer overrides the method responsible for creating a `ReactRootView` instance or uses `RNGestureHandlerEnabledRootView`. Additionally, remove the import statement for `RNGestureHandlerEnabledRootView`:
2073
2074```java
2075package com.swmansion.gesturehandler.react.example;
2076
2077import com.facebook.react.ReactActivity;
2078// Remove this line:
2079// import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
2080
2081public class MainActivity extends ReactActivity {
2082
2083 // Remove these lines:
2084 /*
2085 @Override
2086 protected ReactActivityDelegate createReactActivityDelegate() {
2087 return new ReactActivityDelegate(this, getMainComponentName()) {
2088 @Override
2089 protected ReactRootView createRootView() {
2090 return new RNGestureHandlerEnabledRootView(MainActivity.this);
2091 }
2092 };
2093 }
2094 */
2095}
2096```
2097
2098### Verify App Functionality
2099
2100Some libraries (such as React Navigation) already utilize `GestureHandlerRootView` to enable gesture interactions. If gestures in your app function correctly after removing `RNGestureHandlerEnabledRootView`, you can skip the next step.
2101
2102### Update Your JavaScript Code
2103
2104Replace any usage of `RNGestureHandlerEnabledRootView` with `<GestureHandlerRootView>` or `gestureHandlerRootHOC`. For example:
2105
2106```jsx
2107export default function App() {
2108 return (
2109 <GestureHandlerRootView style={{ flex: 1 }}>
2110 {/* content */}
2111 </GestureHandlerRootView>
2112 )
2113}
2114```
2115
2116**Note:** `GestureHandlerRootView` behaves like a standard `View`. To ensure it fills the screen, you must pass `{ flex: 1 }`, similar to how you would with a regular View. By default, it will take on the size of its nested content.
2117
2118## RotationGestureHandler
2119
2120> **Warning:**\
2121> The old API will be deprecated in future versions of Gesture Handler. It is recommended to migrate to the gestures API. Refer to our upgrading guide for more details.
2122
2123The `RotationGestureHandler` is a continuous gesture handler designed to recognize and track rotation gestures. Activation occurs when fingers are placed on the screen and move appropriately.
2124
2125This handler provides callbacks for continuous tracking, offering insights into the gesture's characteristics such as the amount of rotation (in radians), the focal point or anchor of the rotation, and its instantaneous velocity.
2126
2127On iOS, this functionality is implemented using `UIRotationGestureRecognizer`, while on Android it is developed from scratch.
2128
2129### Properties
2130
2131The properties specific to `RotationGestureHandler` do not extend those provided by the base handler class.
2132
2133### Event Data
2134
2135In addition to the event attributes available in the base handler class, `RotationGestureHandler` includes the following gesture-specific attributes:
2136
2137- **rotation**: The amount of rotation, measured in radians, from the gesture's focal point (anchor).
2138- **velocity**: The instantaneous velocity of the gesture, expressed in points per second.
2139- **anchorX**: The X coordinate of the gesture's central focal point (anchor), measured in points.
2140- **anchorY**: The Y coordinate of the gesture's central focal point (anchor), measured in points.
2141
2142### Example
2143
2144Below is an example demonstrating how to use `RotationGestureHandler`:
2145
2146```typescript
2147class RotableBox extends React.Component {
2148 _rotate = new Animated.Value(0);
2149
2150 _rotateStr = this._rotate.interpolate({
2151 inputRange: [-100, 100],
2152 outputRange: ['-100rad', '100rad'],
2153 });
2154
2155 _lastRotate = 0;
2156
2157 _onRotateGestureEvent = Animated.event(
2158 [{ nativeEvent: { rotation: this._rotate } }],
2159 { useNativeDriver: USE_NATIVE_DRIVER }
2160 );
2161
2162 _onRotateHandlerStateChange = (event) => {
2163 if (event.nativeEvent.oldState === State.ACTIVE) {
2164 this._lastRotate += event.nativeEvent.rotation;
2165 this._rotate.setOffset(this._lastRotate);
2166 this._rotate.setValue(0);
2167 }
2168 };
2169
2170 render() {
2171 return (
2172 <RotationGestureHandler
2173 onGestureEvent={this._onRotateGestureEvent}
2174 onHandlerStateChange={this._onRotateHandlerStateChange}>
2175 <Animated.Image
2176 style={[
2177 styles.pinchableImage,
2178 {
2179 transform: [{ perspective: 200 }, { rotate: this._rotateStr }],
2180 },
2181 ]}
2182 />
2183 </RotationGestureHandler>
2184 );
2185 }
2186}
2187```
2188
2189This example illustrates how to create a rotatable box using `RotationGestureHandler`, with continuous tracking of rotation gestures.
2190
2191## FlingGestureHandler
2192
2193> **Warning:**\
2194> The old API will be deprecated in future versions of Gesture Handler. It is recommended to migrate to the gestures API. Refer to our upgrading guide for more details.
2195
2196The `FlingGestureHandler` is a discrete gesture handler that activates when movement is sufficiently long and fast. Activation occurs if the movement duration is short enough. Once activated, it transitions to an END state upon finger release. If the finger is lifted before activation, the gesture will not be recognized. On iOS, this handler uses `UISwipeGestureRecognizer`, while on Android, it's implemented from scratch.
2197
2198### Properties
2199
2200In addition to properties inherited from the base handler class, `FlingGestureHandler` includes specific properties:
2201
2202#### `direction`
2203
2204Specifies the allowed direction(s) of movement. You can define one or multiple directions in a single parameter:
2205
2206```typescript
2207direction={Directions.RIGHT | Directions.LEFT}
2208```
2209
2210or
2211
2212```typescript
2213direction={Directions.DOWN}
2214```
2215
2216#### `numberOfPointers`
2217
2218Determines the exact number of pointers required to recognize the fling gesture.
2219
2220### Event Data
2221
2222In addition to event attributes from the base handler class, `FlingGestureHandler` provides specific gesture event attributes:
2223
2224#### `x`
2225
2226Represents the X coordinate of the current pointer position (either a single finger or the leading pointer in multi-touch scenarios) relative to the view attached to the handler. The value is expressed in point units.
2227
2228#### `y`
2229
2230Represents the Y coordinate of the current pointer position (either a single finger or the leading pointer in multi-touch scenarios) relative to the view attached to the handler. The value is expressed in point units.
2231
2232#### `absoluteX`
2233
2234Represents the X coordinate of the current pointer position (either a single finger or the leading pointer in multi-touch scenarios) relative to the window, expressed in point units. It's recommended over `x` when the original view can be transformed due to gestures.
2235
2236#### `absoluteY`
2237
2238Represents the Y coordinate of the current pointer position (either a single finger or the leading pointer in multi-touch scenarios) relative to the window, expressed in point units. It's recommended over `y` when the original view can be transformed due to gestures.
2239
2240### Example
2241
2242Below is an example demonstrating how to use `FlingGestureHandler`:
2243
2244```typescript
2245const LongPressButton = () => (
2246 <FlingGestureHandler
2247 direction={Directions.RIGHT | Directions.LEFT}
2248 onHandlerStateChange={({ nativeEvent }) => {
2249 if (nativeEvent.state === State.ACTIVE) {
2250 Alert.alert("I'm flinged!");
2251 }
2252 }}>
2253 <View style={styles.box} />
2254 </FlingGestureHandler>
2255);
2256```
2257
2258This example shows a button that triggers an alert when flinged to the right or left.
2259
2260## Quick start
2261
2262RNGH2 simplifies adding gestures to your application. To implement a gesture, wrap the target view with `GestureDetector`, define the desired gesture, and pass it to the detector.
2263
2264### Example: Dragging a Ball
2265
2266To illustrate using this API, we'll create an app where you can drag a ball around. This requires integrating `react-native-gesture-handler` for gestures and `react-native-reanimated` for animations.
2267
2268#### Step 1: Define Styles
2269
2270First, define the necessary styles:
2271
2272```typescript
2273import { StyleSheet } from "react-native"
2274
2275const styles = StyleSheet.create({
2276 ball: {
2277 width: 100,
2278 height: 100,
2279 borderRadius: 100,
2280 backgroundColor: "blue",
2281 alignSelf: "center",
2282 },
2283})
2284```
2285
2286#### Step 2: Create the Ball Component
2287
2288Next, write the `Ball` component:
2289
2290```typescript
2291import { GestureDetector } from 'react-native-gesture-handler';
2292import Animated from 'react-native-reanimated';
2293
2294function Ball() {
2295 return (
2296 <GestureDetector>
2297 <Animated.View style={[styles.ball]} />
2298 </GestureDetector>
2299 );
2300}
2301```
2302
2303#### Step 3: Define Shared Values and Animated Styles
2304
2305Define shared values to track the ball's position and create animated styles for positioning:
2306
2307```typescript
2308import {
2309 useSharedValue,
2310 useAnimatedStyle,
2311 withSpring,
2312} from "react-native-reanimated"
2313
2314function Ball() {
2315 const isPressed = useSharedValue(false)
2316 const offset = useSharedValue({ x: 0, y: 0 })
2317
2318 const animatedStyles = useAnimatedStyle(() => {
2319 return {
2320 transform: [
2321 { translateX: offset.value.x },
2322 { translateY: offset.value.y },
2323 { scale: withSpring(isPressed.value ? 1.2 : 1) },
2324 ],
2325 backgroundColor: isPressed.value ? "yellow" : "blue",
2326 }
2327 })
2328
2329 // ...
2330}
2331```
2332
2333#### Step 4: Apply Animated Styles
2334
2335Add the animated styles to the ball's styles:
2336
2337```typescript
2338// ...
2339return (
2340 <GestureDetector>
2341 <Animated.View style={[styles.ball, animatedStyles]} />
2342 </GestureDetector>
2343);
2344// ...
2345```
2346
2347#### Step 5: Define and Assign the Pan Gesture
2348
2349Finally, define the pan gesture and assign it to the detector:
2350
2351```typescript
2352import { Gesture } from 'react-native-gesture-handler';
2353
2354function Ball() {
2355 const start = useSharedValue({ x: 0, y: 0 });
2356 const gesture = Gesture.Pan()
2357 .onBegin(() => {
2358 isPressed.value = true;
2359 })
2360 .onUpdate((e) => {
2361 offset.value = {
2362 x: e.translationX + start.value.x,
2363 y: e.translationY + start.value.y,
2364 };
2365 })
2366 .onEnd(() => {
2367 start.value = {
2368 x: offset.value.x,
2369 y: offset.value.y,
2370 };
2371 })
2372 .onFinalize(() => {
2373 isPressed.value = false;
2374 });
2375
2376 // ...
2377}
2378
2379// ...
2380return (
2381 <GestureDetector gesture={gesture}>
2382 <Animated.View style={[styles.ball, animatedStyles]} />
2383 </GestureDetector>
2384);
2385// ...
2386```
2387
2388**Note:** The `start` shared value stores the ball's position when grabbed to ensure correct positioning later, as we only have access to translation relative to the gesture's starting point.
2389
2390Now, add the `Ball` component to a view in your app to see it in action!
2391
2392## Native gesture
2393
2394A gesture that integrates with other touch handling components within RNGH's gesture system. This integration facilitates interactions between gestures and native components, allowing them to establish relationships with other gestures.
2395
2396When utilized, the native component should be a direct child of a `GestureDetector`.
2397
2398### Example
2399
2400This example demonstrates rendering a `ScrollView` containing multiple colored rectangles. Each rectangle includes a black section that, when touched, disables the `ScrollView` for the duration of the `Pan` gesture.
2401
2402```typescript
2403import { View, ScrollView } from 'react-native';
2404import { Gesture, GestureDetector } from 'react-native-gesture-handler';
2405
2406const COLORS = ['red', 'green', 'blue', 'purple', 'orange', 'cyan'];
2407
2408export default function App() {
2409 const native = Gesture.Native();
2410
2411 return (
2412 <GestureDetector gesture={native}>
2413 <ScrollView style={{ flex: 1 }}>
2414 <ScrollableContent scrollGesture={native} />
2415 </ScrollView>
2416 </GestureDetector>
2417 );
2418}
2419
2420function ScrollableContent({ scrollGesture }) {
2421 return (
2422 <View>
2423 {COLORS.map((color) => (
2424 <Rectangle key={color} color={color} scrollGesture={scrollGesture} />
2425 ))}
2426 </View>
2427 );
2428}
2429
2430function Rectangle({ color, scrollGesture }) {
2431 const pan = Gesture.Pan().blocksExternalGesture(scrollGesture);
2432
2433 return (
2434 <View
2435 key={color}
2436 style={{ width: '100%', height: 250, backgroundColor: color }}>
2437 <GestureDetector gesture={pan}>
2438 <View style={{ width: '100%', height: 50, backgroundColor: 'black' }} />
2439 </GestureDetector>
2440 </View>
2441 );
2442}
2443```
2444
2445### Remarks
2446
2447- The `Native` gesture can be used in gesture composition and cross-component interactions like any other gesture. This allows you to block a native component during the gesture or make it work alongside another gesture.
2448
2449**Warning**: Do not use the `Native` gesture with components exported by React Native Gesture Handler, as they already have a native gesture handler applied. Attaching a native gesture twice may cause the components to malfunction.
2450
2451### Configuration
2452
2453#### Properties Specific to `NativeGesture`
2454
2455##### `shouldActivateOnStart(value: boolean)` (**Android only**)
2456
2457When set to `true`, the underlying handler will activate unconditionally upon receiving any touches in the `BEGAN` or `UNDETERMINED` state.
2458
2459##### `disallowInterruption(value: boolean)`
2460
2461When set to `true`, cancels all other gesture handlers when this `NativeViewGestureHandler` changes its state to `ACTIVE`.
2462
2463#### Properties Common to All Gestures
2464
2465##### `enabled(value: boolean)`
2466
2467Indicates whether the handler should analyze touch events. When set to `false`, the handler's state will **never** become `ACTIVE`. If updated during gesture recognition, it will immediately change to `FAILED` or `CANCELLED`. Default is `true`.
2468
2469##### `shouldCancelWhenOutside(value: boolean)`
2470
2471When `true`, the handler cancels or fails recognition if a finger leaves the connected view area. The default varies by handler type; most handlers default to `false`, except for `LongPressGesture` and `TapGesture`, which default to `true`.
2472
2473##### `hitSlop(settings)`
2474
2475Controls the part of the connected view where gesture recognition can begin. Negative numbers reduce the view bounds evenly on all sides. Alternatively, specify reductions for each side (`left`, `right`, `top`, `bottom`) or use `horizontal`/`vertical`. You can also set `width` and `height` to restrict activation to edges.
2476
2477**Important**: This parameter primarily reduces gesture activation areas. It supports non-positive values (0 or lower) on all sides, with positive values supported only on Android for expanding beyond view bounds but not past parent view bounds. For cross-platform support, use React Native's View hitSlop property.
2478
2479##### `withRef(ref)`
2480
2481Sets a ref to the gesture object for interoperability with the old API.
2482
2483##### `withTestId(testID)`
2484
2485Assigns a `testID` to the gesture object for querying in tests.
2486
2487##### `cancelsTouchesInView(value)` (**iOS only**)
2488
2489Accepts a boolean. When `true`, cancels touches for native UI components (`UIButton`, `UISwitch`, etc.) when active. Default is `true`.
2490
2491##### `runOnJS(value: boolean)`
2492
2493When `react-native-reanimated` is installed, gesture callbacks are workletized and run on the UI thread by default. This option allows running all callbacks on the JS thread instead, regardless of whether they are worklets or not. Defaults to `false`.
2494
2495##### `simultaneousWithExternalGesture(otherGesture1, otherGesture2, ...)`
2496
2497Marks a gesture for simultaneous recognition with this one.
2498
2499**Important**: This method only marks relations between gestures without composing them. The `otherGestures` need to be added to another detector for recognition by `GestureDetector`.
2500
2501##### `requireExternalGestureToFail(otherGesture1, otherGesture2, ...)`
2502
2503Requires another gesture to fail before this one can activate.
2504
2505##### `blocksExternalGesture(otherGesture1, otherGesture2, ...)`
2506
2507Makes other gestures wait until this gesture fails or doesn't start.
2508
2509**Important**: This method only marks relations between gestures without composing them. The `otherGestures` need to be added to another detector for recognition by `GestureDetector`.
2510
2511##### `activeCursor(value)` (Web only)
2512
2513Specifies the cursor used when the gesture activates, supporting all CSS cursor values (e.g., `"grab"`, `"zoom-in"`). Default is `"auto"`.
2514
2515### Callbacks
2516
2517#### Common to All Gestures
2518
2519##### `onBegin(callback)`
2520
2521Sets a callback called when the gesture handler starts receiving touches. At this point, it's not yet active or recognized.
2522
2523##### `onStart(callback)`
2524
2525Sets a callback called when the gesture is recognized and transitions to an active state.
2526
2527##### `onEnd(callback)`
2528
2529Sets a callback called when a recognized gesture finishes, only if previously active.
2530
2531##### `onFinalize(callback)`
2532
2533Sets a callback called when the handler finalizes handling a gesture—either recognized and finished or failed.
2534
2535##### `onTouchesDown(callback)`
2536
2537Sets a callback for each finger placed on the screen.
2538
2539##### `onTouchesMove(callback)`
2540
2541Sets a callback for each finger movement on the screen.
2542
2543##### `onTouchesUp(callback)`
2544
2545Sets a callback for each finger lifted from the screen.
2546
2547##### `onTouchesCancelled(callback)`
2548
2549Sets a callback for when a finger stops being tracked, such as when a gesture finishes.
2550
2551### Event Data
2552
2553#### Specific to `NativeGesture`
2554
2555##### `pointerInside`
2556
2557Indicates if the gesture was performed inside the containing view (`true`) or outside (`false`).
2558
2559#### Common to All Gestures
2560
2561##### `state`
2562
2563Represents the current state of the handler, expressed as one of the constants in the `State` object exported by the library.
2564
2565##### `numberOfPointers`
2566
2567The number of pointers (fingers) currently on the screen.
2568
2569##### `pointerType`
2570
2571Indicates the type of pointer device used. Represented by the `PointerType` enum:
2572
2573- `TOUCH`: Represents a finger.
2574- `STYLUS`: Represents a stylus or digital pen.
2575- `MOUSE`: Represents a computer mouse.
2576- `KEY`: Represents a keyboard.
2577- `OTHER`: Represents an unknown device type that is not relevant.
2578
2579## PinchGestureHandler
2580
2581> **Warning:**\
2582> The old API will be deprecated in future versions of Gesture Handler. It is recommended to migrate to the gestures API. Refer to our upgrading guide for more details.
2583
2584The `PinchGestureHandler` is a continuous gesture handler designed to recognize pinch gestures, which are commonly used to scale or zoom content on the screen. This handler activates when two fingers touch and move across the screen. The callback function associated with this gesture provides continuous tracking of the pinch gesture, offering insights into velocity, the focal point (anchor) of the gesture, and the scaling factor.
2585
2586The distance between the fingers is represented as a scale factor. Initially, at the start of the gesture, the scale factor is set to 1.0. As the distance between the two fingers increases or decreases, the scale factor adjusts proportionally. Pinch gestures are frequently utilized for resizing objects or content onscreen, such as adjusting the zoom level in map views.
2587
2588On iOS, this handler leverages `UIPinchGestureRecognizer`, while on Android, it is implemented from scratch.
2589
2590### Properties
2591
2592The properties specific to `PinchGestureHandler` do not extend beyond those provided by the base handler class.
2593
2594### Event Data
2595
2596For a comprehensive list of event attributes from the base handler class, refer to its documentation. Below are gesture event attributes unique to `PinchGestureHandler`:
2597
2598- **`scale`:** Represents the scale factor relative to the screen coordinates of the two touch points.
2599
2600- **`velocity`:** Indicates the velocity of the pinch gesture at the current moment, expressed in terms of scale factor per second.
2601
2602- **`focalX`:** The X-axis position (in points) of the center anchor point of the gesture.
2603
2604- **`focalY`:** The Y-axis position (in points) of the center anchor point of the gesture.
2605
2606### Example
2607
2608For a practical demonstration, refer to the scale and rotation example in the Gesture Handler Example App.
2609
2610```typescript
2611import React from 'react';
2612import { Animated, View } from 'react-native';
2613import { PinchGestureHandler, State } from 'react-native-gesture-handler';
2614
2615const USE_NATIVE_DRIVER = true;
2616
2617export class PinchableBox extends React.Component {
2618 _baseScale = new Animated.Value(1);
2619 _pinchScale = new Animated.Value(1);
2620 _scale = Animated.multiply(this._baseScale, this._pinchScale);
2621 _lastScale = 1;
2622
2623 _onPinchGestureEvent = Animated.event(
2624 [{ nativeEvent: { scale: this._pinchScale } }],
2625 { useNativeDriver: USE_NATIVE_DRIVER }
2626 );
2627
2628 _onPinchHandlerStateChange = (event) => {
2629 if (event.nativeEvent.oldState === State.ACTIVE) {
2630 this._lastScale *= event.nativeEvent.scale;
2631 this._baseScale.setValue(this._lastScale);
2632 this._pinchScale.setValue(1);
2633 }
2634 };
2635
2636 render() {
2637 return (
2638 <PinchGestureHandler
2639 onGestureEvent={this._onPinchGestureEvent}
2640 onHandlerStateChange={this._onPinchHandlerStateChange}>
2641 <View style={{ flex: 1 }} collapsable={false}>
2642 <Animated.Image
2643 source={{ uri: 'https://example.com/image.jpg' }}
2644 style={{
2645 width: 200,
2646 height: 200,
2647 transform: [
2648 { perspective: 200 },
2649 { scale: this._scale }
2650 ],
2651 }}
2652 />
2653 </View>
2654 </PinchGestureHandler>
2655 );
2656 }
2657}
2658```
2659
2660This example demonstrates how to implement a pinchable box using `PinchGestureHandler` in React Native. The component tracks the pinch gesture and updates the image's scale accordingly.
2661
2662## Force Touch Gesture Handler
2663
2664The `ForceTouchGestureHandler` is a continuous gesture handler designed to recognize the force of touch. It tracks the pressure applied during a touch on certain iOS devices. The handler activates when the touch pressure meets or exceeds the specified `minForce`. If the pressure surpasses `maxForce`, the handler fails.
2665
2666### Key Features
2667
2668- **Pressure Tracking**: Monitors the pressure of touch, starting from 0.0 and scaling up to 1.0 as pressure increases.
2669- **iOS Implementation**: Utilizes a custom `UIGestureRecognizer` on iOS. No implementation is provided for Android; it simply renders children without additional wrappers.
2670- **Non-Critical Use**: Due to limited device support, this handler should not be used for critical behaviors but can enhance user experience.
2671
2672### Properties
2673
2674#### Inherited from Base Handler Class
2675
2676Refer to the base handler class for common properties.
2677
2678#### Specific to `ForceTouchGestureHandler`
2679
2680##### `minForce`
2681
2682- **Description**: The minimum pressure required to activate the handler.
2683- **Range**: `[0.0, 1.0]`
2684- **Default**: `0.2`
2685
2686##### `maxForce`
2687
2688- **Description**: The maximum allowable pressure before the handler fails.
2689- **Range**: `[0.0, 1.0]`
2690
2691##### `feedbackOnActivation`
2692
2693- **Type**: Boolean
2694- **Description**: Determines if haptic feedback should occur upon activation.
2695
2696### Event Data
2697
2698#### Inherited from Base Handler Class
2699
2700Refer to the base handler class for common event attributes.
2701
2702#### Specific to `ForceTouchGestureHandler`
2703
2704##### `force`
2705
2706- **Description**: Represents the pressure of a touch.
2707
2708### Static Method
2709
2710#### `forceTouchAvailable`
2711
2712- **Usage**: Check if `ForceTouchGestureHandler` is supported using `ForceTouchGestureHandler.forceTouchAvailable`.
2713
2714### Example Usage
2715
2716```typescript
2717<ForceTouchGestureHandler
2718 minForce={0}
2719 onGestureEvent={this._onGestureEvent}
2720 onHandlerStateChange={this._onHandlerStateChange}>
2721 <Animated.View
2722 style={[
2723 styles.box,
2724 { transform: [{ scale: Animated.add(1, this.force) }] },
2725 ]}
2726 />
2727</ForceTouchGestureHandler>
2728```
2729
2730**Note**: For a detailed example, refer to the Gesture Handler Example App.
2731
2732## Manual gesture
2733
2734A manual gesture lacks specific activation criteria and event data. Its state must be managed manually using a state manager, ensuring it doesn't fail when all pointers are lifted from the screen.
2735
2736### Reference
2737
2738```typescript
2739import { GestureDetector, Gesture } from 'react-native-gesture-handler';
2740
2741function App() {
2742 const manual = Gesture.Manual();
2743
2744 return (
2745 <GestureDetector gesture={manual}>
2746 <Animated.View />
2747 </GestureDetector>
2748 );
2749}
2750```
2751
2752### Configuration
2753
2754#### Common Properties for All Gestures:
2755
2756##### `enabled(value: boolean)`
2757
2758Determines if the handler analyzes touch events. When set to `false`, the handler's state will **never** become `ACTIVE`. If updated during gesture recognition, it changes to `FAILED` or `CANCELLED` based on its current state. Default is `true`.
2759
2760##### `shouldCancelWhenOutside(value: boolean)`
2761
2762If `true`, the handler cancels or fails recognition when a finger leaves the connected view's area. Defaults vary by handler type; most are `false`, except for `LongPressGesture` and `TapGesture`, which default to `true`.
2763
2764##### `hitSlop(settings)`
2765
2766Controls the gesture activation area within the connected view. Negative numbers reduce bounds evenly on all sides. Alternatively, specify reductions with `left`, `right`, `top`, or `bottom`. Use `horizontal` or `vertical` for combined adjustments. `width` and `height` allow edge-specific activations (e.g., `left: 0` and `width: 20`). Note: Primarily reduces activation area; non-positive values are supported, with Android allowing positive values within parent bounds.
2767
2768**IMPORTANT:** This parameter is designed to reduce the gesture activation area. It supports only non-positive values for all parameters except `width` and `height`. On Android, positive values are allowed but limited by parent view bounds. Use React Native's View hitSlop property for cross-platform edge effects.
2769
2770##### `withRef(ref)`
2771
2772Sets a ref to the gesture object for interoperability with older APIs.
2773
2774##### `withTestId(testID)`
2775
2776Assigns a `testID` to the gesture object, enabling test queries.
2777
2778##### `cancelsTouchesInView(value)` (**iOS only**)
2779
2780Accepts a boolean. When `true`, cancels touches for native UI components (`UIButton`, `UISwitch`, etc.) when active. Default is `true`.
2781
2782##### `runOnJS(value: boolean)`
2783
2784When `react-native-reanimated` is installed, callbacks are workletized and run on the UI thread by default. This option allows running all callbacks on the JS thread instead. Defaults to `false`.
2785
2786##### `simultaneousWithExternalGesture(otherGesture1, otherGesture2, ...)`
2787
2788Marks a gesture for simultaneous recognition with this one.
2789
2790**IMPORTANT:** This method only marks relations between gestures without composing them. `GestureDetector` will not recognize `otherGestures`; they must be added to another detector for recognition.
2791
2792##### `requireExternalGestureToFail(otherGesture1, otherGesture2, ...)`
2793
2794Requires another gesture to fail before activation.
2795
2796##### `blocksExternalGesture(otherGesture1, otherGesture2, ...)`
2797
2798Waits for this gesture to fail (or not start) before activating others.
2799
2800**IMPORTANT:** This method only marks relations between gestures without composing them. `GestureDetector` will not recognize `otherGestures`; they must be added to another detector for recognition.
2801
2802##### `activeCursor(value)` (Web only)
2803
2804Specifies the cursor used when the gesture activates, supporting all CSS cursor values (e.g., `"grab"`, `"zoom-in"`). Default is `"auto"`.
2805
2806### Callbacks
2807
2808#### Common Callbacks for All Gestures:
2809
2810##### `onBegin(callback)`
2811
2812Called when the handler starts receiving touches but hasn't yet recognized the gesture.
2813
2814##### `onStart(callback)`
2815
2816Triggered when the gesture is recognized and transitions to an active state.
2817
2818##### `onEnd(callback)`
2819
2820Invoked when a recognized gesture finishes, provided it was previously active.
2821
2822##### `onFinalize(callback)`
2823
2824Called when the handler finalizes handling a gesture—either recognized and finished or failed.
2825
2826##### `onTouchesDown(callback)`
2827
2828Executed every time a finger touches the screen.
2829
2830##### `onTouchesMove(callback)`
2831
2832Triggered whenever a finger moves on the screen.
2833
2834##### `onTouchesUp(callback)`
2835
2836Invoked each time a finger is lifted from the screen.
2837
2838##### `onTouchesCancelled(callback)`
2839
2840Called when a finger stops being tracked, such as when a gesture finishes.
2841
2842#### Common Callbacks for All Continuous Gestures:
2843
2844##### `onUpdate(callback)`
2845
2846Executed every time an active gesture receives an update.
2847
2848##### `onChange(callback)`
2849
2850Triggered with each update during an active gesture, providing change information relative to the last event.
2851
2852### Event Data
2853
2854#### Attributes Common to All Gestures:
2855
2856##### `state`
2857
2858Represents the handler's current state using constants from the `State` object exported by the library.
2859
2860##### `numberOfPointers`
2861
2862Indicates the number of pointers (fingers) currently on the screen.
2863
2864##### `pointerType`
2865
2866Specifies the pointer device type, represented by the `PointerType` enum with fields:
2867
2868- `TOUCH`: Finger
2869- `STYLUS`: Stylus or digital pen
2870- `MOUSE`: Computer mouse
2871- `KEY`: Keyboard
2872- `OTHER`: Unknown device type
2873
2874## Make sure to migrate off the \`RNGestureHandlerEnabledRootView\` (Android only)
2875
2876The `RNGestureHandlerEnabledRootView`, required in Gesture Handler 1 for overriding `createRootView`, was deprecated in version 2.0 and removed by version 2.4 due to its association with difficult-to-debug crashes. If you're still using it, refer to the guide on migrating off RNGHEnabledRootView.
2877
2878### Upgrading to the New API
2879
2880Gesture Handler 2 introduces a new Gesture API along with the `GestureDetector` component, simplifying gesture declaration by reducing boilerplate code. Instead of separate components for each gesture type, `GestureDetector` attaches gestures based on configuration objects created using the `Gesture` object. Here's an example:
2881
2882```typescript
2883const tapGesture = Gesture.Tap().onStart(() => {
2884 console.log('Tap!');
2885});
2886
2887return (
2888 <GestureDetector gesture={tapGesture}>
2889 <View />
2890 </GestureDetector>
2891);
2892```
2893
2894The new API eliminates `onGestureEvent` and `onHandlerStateChange`, handling state transitions internally. Key callbacks include:
2895
2896- **`onBegin`**: Triggered when the gesture enters the `BEGAN` state.
2897- **`onStart`**: Activated when the gesture moves from `BEGAN` to `ACTIVE`.
2898- **`onUpdate`**: Called during each event in the `ACTIVE` state, replacing `onGestureEvent`.
2899- **`onChange`**: Follows `onUpdate`, providing change values since the last event.
2900- **`onEnd`**: Triggered when transitioning from `ACTIVE` to `END`, `FAILED`, or `CANCELLED`. The reason for ending is determined by a second argument.
2901- **`onFinalize`**: Called upon entering `END`, `FAILED`, or `CANCELLED`, regardless of whether the gesture was `ACTIVE`.
2902
2903The distinction between `onEnd` and `onFinalize` lies in their activation: `onEnd` triggers only if the gesture was `ACTIVE`, while `onFinalize` activates if it reached `BEGAN`. Use `onEnd` for cleanup post-`onStart`, and `onFinalize` after `onBegin`.
2904
2905#### Configuring Gestures
2906
2907Gestures are configured using a builder-like pattern, where methods replace properties. For instance:
2908
2909```typescript
2910return (
2911 <TapGestureHandler
2912 numberOfTaps={2}
2913 maxDurationMs={500}
2914 maxDelayMs={500}
2915 maxDist={10}
2916 onHandlerStateChange={({ nativeEvent }) => {
2917 if (nativeEvent.state === State.ACTIVE) {
2918 console.log('Tap!');
2919 }
2920 }}>
2921 <View />
2922 </TapGestureHandler>
2923);
2924```
2925
2926This can be equivalently configured as:
2927
2928```typescript
2929const tapGesture = Gesture.Tap()
2930 .numberOfTaps(2)
2931 .maxDuration(500)
2932 .maxDelay(500)
2933 .maxDistance(10)
2934 .onStart(() => {
2935 console.log('Tap!');
2936 });
2937
2938return (
2939 <GestureDetector gesture={tapGesture}>
2940 <View />
2941 </GestureDetector>
2942);
2943```
2944
2945Refer to the API Reference under Gestures for available modifiers.
2946
2947#### Using Multiple Gestures on a Single View
2948
2949Previously, stacking multiple gestures required deep component trees with `Animated.View` layers. For example:
2950
2951```typescript
2952return (
2953 <TapGestureHandler ... >
2954 <Animated.View>
2955 <PanGestureHandler ... >
2956 <Animated.View>
2957 <PinchGestureHandler ... >
2958 <YourView />
2959 </PinchGestureHandler>
2960 </Animated.View>
2961 </PanGestureHandler>
2962 </Animated.View>
2963 </TapGestureHandler>
2964);
2965```
2966
2967With `GestureDetector`, use the Gesture Composition API to stack gestures:
2968
2969```typescript
2970const tapGesture = Gesture.Tap();
2971const panGesture = Gesture.Pan();
2972const pinchGesture = Gesture.Pinch();
2973
2974return (
2975 <GestureDetector gesture={Gesture.Race(tapGesture, panGesture, pinchGesture)}>
2976 <YourView />
2977 </GestureDetector>
2978);
2979```
2980
2981Use `Gesture.Simultaneous` for simultaneous recognition and `Gesture.Exclusive` for exclusive gestures.
2982
2983#### Replacing `waitFor` and `simultaneousHandlers`
2984
2985For relations between gestures on the same view, use the Gesture Composition API. For different views or old gesture handlers, replace `simultaneousHandlers` with `simultaneousWithExternalGesture`, and `waitFor` with `requireExternalGestureToFail`. Use `.withRef(refObject)` to pass a ref object to an old handler.
2986
2987## Composed gestures
2988
2989Composed gestures such as `Race`, `Simultaneous`, and `Exclusive` offer a straightforward method for establishing relationships between different gestures. For further information, refer to the section on Gesture Composition.
2990
2991### Reference Example
2992
2993```typescript
2994import { GestureDetector, Gesture } from 'react-native-gesture-handler';
2995
2996function App() {
2997 const panGesture = Gesture.Pan();
2998 const longPressGesture = Gesture.LongPress();
2999
3000 // Compose gestures using Race
3001 const composedGesture = Gesture.Race(panGesture, longPressGesture);
3002
3003 return (
3004 <GestureDetector gesture={composedGesture}>
3005 <Animated.View />
3006 </GestureDetector>
3007 );
3008}
3009```
3010
3011This example demonstrates how to use the `Race` method to compose two gestures: a pan gesture and a long press gesture. The composed gesture is then used within a `GestureDetector` component, which wraps an `Animated.View`.
3012
3013## Common handler properties
3014
3015**Warning:** The old API will be removed in future versions of Gesture Handler. Please migrate to the gestures API instead. Refer to our upgrading guide for more information.
3016
3017This page covers the common set of properties that all gesture handler components expose.
3018
3019### Units
3020
3021All handler component properties and event attributes representing onscreen dimensions are expressed in screen density-independent units known as "points." These units are commonly used in the React Native ecosystem (e.g., in the layout system). They do not map directly to physical pixels but correspond to iOS's points and Android's dp units.
3022
3023### Properties
3024
3025This section describes properties applicable to all gesture handler components:
3026
3027#### `enabled`
3028
3029- **Type:** Boolean
3030- **Description:** Indicates whether the handler should analyze a stream of touch events. When set to `false`, the handler's state will never become `ACTIVE`. If updated while recognizing a gesture, it changes to `FAILED` or `CANCELLED` based on its current state.
3031- **Default Value:** `true`
3032
3033#### `shouldCancelWhenOutside`
3034
3035- **Type:** Boolean
3036- **Description:** When `true`, the handler cancels or fails recognition if the finger leaves the connected view's area. The default value varies by handler type; most handlers default to `false`, except for `LongPressGestureHandler` and `TapGestureHandler`, which default to `true`.
3037
3038#### `cancelsTouchesInView` (**iOS only**)
3039
3040- **Type:** Boolean
3041- **Description:** When `true`, the handler cancels touches for native UI components (e.g., `UIButton`, `UISwitch`) it's attached to when active.
3042- **Default Value:** `true`
3043
3044#### `simultaneousHandlers`
3045
3046- **Type:** React ref object or array of refs
3047- **Description:** Allows activation even if other handlers provided by their refs are in an `ACTIVE` state. Prevents these handlers from cancelling the current handler upon activation. See cross-handler interaction for more details.
3048
3049#### `waitFor`
3050
3051- **Type:** React ref object or array of refs
3052- **Description:** The handler will not activate as long as handlers provided by their refs are in the `BEGAN` state. See cross-handler interaction for more details.
3053
3054#### `hitSlop`
3055
3056- **Description:** Controls the area within the connected view where gesture recognition can begin. A negative number reduces the view's bounds evenly on all sides. Alternatively, an object can specify reductions for each side (`left`, `right`, `top`, `bottom`) or use `horizontal`/`vertical`. The object may also include `width` and `height` attributes to restrict activation to edges.
3057- **Note:** Primarily designed to reduce the gesture activation area; supported values are non-positive (0 or lower) on all platforms except Android, where positive values expand beyond view bounds but not past parent view bounds. Use React Native's View hitSlop property for cross-platform support.
3058
3059#### `userSelect` (**Web only**)
3060
3061- **Type:** `"none" | "auto" | "text"`
3062- **Description:** Specifies the `userSelect` property applied to the underlying view.
3063- **Default Value:** `"none"`
3064
3065#### `activeCursor` (**Web only**)
3066
3067- **Type:** CSS cursor value (e.g., `"grab"`, `"zoom-in"`)
3068- **Description:** Specifies the cursor used when a gesture activates.
3069- **Default Value:** `"auto"`
3070
3071#### `onGestureEvent`
3072
3073- **Type:** Callback or `Animated.event`
3074- **Description:** Triggered for each touch event while the handler is in an ACTIVE state. The event payload varies by handler type, with common attributes documented below and specific ones on corresponding handler pages.
3075
3076#### `onHandlerStateChange`
3077
3078- **Type:** Callback or `Animated.event`
3079- **Description:** Triggered when the handler's state changes. Includes the same payload as `onGestureEvent` plus an `oldState` attribute representing the previous state before the change.
3080
3081### Event Data
3082
3083This section describes attributes of the event object provided to `onGestureEvent` and `onHandlerStateChange` callbacks:
3084
3085#### `state`
3086
3087- **Description:** Current state of the handler, expressed as one of the constants in the `State` object exported by the library. Refer to the handler state section for more details.
3088
3089#### `numberOfPointers`
3090
3091- **Description:** Represents the number of pointers (fingers) currently on the screen.
3092
3093## Gestures (Version: 2.x)
3094
3095### GestureDetector
3096
3097The `GestureDetector` serves as the core component within RNGH2, tasked with creating and updating native gesture handlers based on the configuration of provided gestures. A key enhancement over previous versions is its ability to recognize multiple gestures simultaneously through gesture composition. It's important to note that `GestureDetector` does not support integration with the Animated API or Reanimated 1.
3098
3099### Gesture
3100
3101A `Gesture` object facilitates the creation and combination of various gestures, enabling more complex interactions.
3102
3103### Pan Gesture
3104
3105```typescript
3106<InteractiveExample />
3107```
3108
3109### Tap Gesture
3110
3111```typescript
3112<InteractiveExample />
3113```
3114
3115### Long Press Gesture
3116
3117```typescript
3118<InteractiveExample />
3119```
3120
3121### Rotation Gesture
3122
3123```typescript
3124<InteractiveExample />
3125```
3126
3127### Pinch Gesture
3128
3129```typescript
3130<InteractiveExample />
3131```
3132
3133### Fling Gesture
3134
3135```typescript
3136<InteractiveExample />
3137```
3138
3139### Hover Gesture
3140
3141```typescript
3142<InteractiveExample />
3143```
3144
3145### Force Touch Gesture
3146
3147This continuous gesture detects the force of a touch, allowing for pressure tracking on certain iOS devices.
3148
3149### Native Gesture
3150
3151A `Native Gesture` enables other touch handling components to function within RNGH's gesture system. This integration facilitates seamless interactions between gestures and native components, enabling them to establish relationships with other gestures.
3152
3153### Manual Gesture
3154
3155A `Manual Gesture` lacks specific activation criteria or event data. Its state must be managed manually using a state manager. Unlike other gestures, it does not fail when all pointers are removed from the screen.
3156
3157### Composed Gestures
3158
3159Composed gestures (Race, Simultaneous, Exclusive) offer an easy method for establishing relationships between gestures. For more information, refer to Gesture Composition.
3160
3161### Touch Events
3162
3163Attributes of touch events include various properties that define their behavior and characteristics.
3164
3165### Gesture State Manager
3166
3167The `GestureStateManager` allows manual control over gesture states. Note that react-native-reanimated is required for its use, as it enables synchronous execution of methods within worklets.
3168
3169## Touch events
3170
3171### Touch Event Attributes
3172
3173- **eventType**: Indicates the type of event, such as finger placement on the screen, movement, lifting, or cancellation.
3174
3175- **changedTouches**: An array containing objects for each touch affected by the event (placed down, moved, lifted, or cancelled).
3176
3177- **allTouches**: An array with objects representing all active touches.
3178
3179- **numberOfTouches**: A count of currently active touches.
3180
3181> **Caution**: Do not rely on the order of items in `touches` as it may change during a gesture. Use the `id` attribute to track individual touches across events.
3182
3183### PointerData Attributes
3184
3185- **id**: A unique number representing the touch's ID, used for tracking the touch between events since the ID remains constant while being tracked.
3186
3187- **x**: The X coordinate of the current position of the touch relative to the view attached to the `GestureDetector`, expressed in point units.
3188
3189- **y**: The Y coordinate of the current position of the touch relative to the view attached to the `GestureDetector`, expressed in point units.
3190
3191- **absoluteX**: The X coordinate of the current position of the touch relative to the window, expressed in point units. Recommended for use when the original view can be transformed due to a gesture.
3192
3193- **absoluteY**: The Y coordinate of the current position of the touch relative to the window, expressed in point units. Recommended for use when the original view can be transformed due to a gesture.
3194
3195## Gesture state manager
3196
3197The `GestureStateManager` provides manual control over gesture states, requiring `react-native-reanimated` for synchronous execution of methods within worklets.
3198
3199### Methods Overview
3200
3201#### `begin()`
3202
3203- **Purpose**: Transition the gesture to the `BEGAN` state.
3204- **Effectiveness**: Ineffective if the gesture is already active or has finished.
3205
3206#### `activate()`
3207
3208- **Purpose**: Transition the gesture to the `ACTIVE` state.
3209- **Effectiveness**: Ineffective if the handler is currently active or has finished. Activation may be delayed for gestures marked as `exclusive` until a higher-priority gesture fails.
3210
3211#### `end()`
3212
3213- **Purpose**: Transition the gesture to the `END` state.
3214- **Effectiveness**: Ineffective if the handler has already completed its process.
3215
3216#### `fail()`
3217
3218- **Purpose**: Transition the gesture to the `FAILED` state.
3219- **Effectiveness**: Ineffective if the handler has already finished.
3220
3221## Touch events
3222
3223### Touch Event Attributes
3224
3225- **eventType**: Indicates the type of event, such as finger placement on the screen, movement, lifting, or cancellation.
3226
3227- **changedTouches**: An array containing objects for each touch affected by the event (placed down, moved, lifted, or cancelled).
3228
3229- **allTouches**: An array with objects representing all active touches.
3230
3231- **numberOfTouches**: A count of currently active touches.
3232
3233> **Caution**: Do not rely on the order of items in `touches` as it may change during a gesture. Use the `id` attribute to track individual touches across events.
3234
3235### PointerData Attributes
3236
3237- **id**: A unique number representing the touch's ID, used for tracking the touch between events since the ID remains constant while being tracked.
3238
3239- **x**: The X coordinate of the current position of the touch relative to the view attached to the `GestureDetector`, expressed in point units.
3240
3241- **y**: The Y coordinate of the current position of the touch relative to the view attached to the `GestureDetector`, expressed in point units.
3242
3243- **absoluteX**: The X coordinate of the current position of the touch relative to the window, expressed in point units. Recommended for use when the original view can be transformed due to a gesture.
3244
3245- **absoluteY**: The Y coordinate of the current position of the touch relative to the window, expressed in point units. Recommended for use when the original view can be transformed due to a gesture.
3246
3247## Gesture state manager
3248
3249The `GestureStateManager` provides manual control over gesture states, requiring `react-native-reanimated` for synchronous execution of methods within worklets.
3250
3251### Methods Overview
3252
3253#### `begin()`
3254
3255- **Purpose**: Transition the gesture to the `BEGAN` state.
3256- **Effectiveness**: Ineffective if the gesture is already active or has finished.
3257
3258#### `activate()`
3259
3260- **Purpose**: Transition the gesture to the `ACTIVE` state.
3261- **Effectiveness**: Ineffective if the handler is currently active or has finished. Activation may be delayed for gestures marked as `exclusive` until a higher-priority gesture fails.
3262
3263#### `end()`
3264
3265- **Purpose**: Transition the gesture to the `END` state.
3266- **Effectiveness**: Ineffective if the handler has already completed its process.
3267
3268#### `fail()`
3269
3270- **Purpose**: Transition the gesture to the `FAILED` state.
3271- **Effectiveness**: Ineffective if the handler has already finished.
3272
3273## GestureDetector
3274
3275The `GestureDetector` is a key component within RNGH2, tasked with creating and updating native gesture handlers based on the configuration of provided gestures. A notable advancement over previous gesture handlers is its ability to recognize multiple gestures simultaneously through gesture composition. It's important to note that `GestureDetector` does not support the Animated API or Reanimated 1.
3276
3277### Reference
3278
3279```typescript
3280import { Gesture, GestureDetector } from 'react-native-gesture-handler';
3281
3282function App() {
3283 const tap = Gesture.Tap();
3284 return (
3285 <GestureDetector gesture={tap}>
3286 <Animated.View />
3287 </GestureDetector>
3288 );
3289}
3290```
3291
3292### Properties
3293
3294#### `gesture`
3295
3296This property accepts a gesture object that includes configuration and callbacks. It can be any of the base gestures (`Tap`, `Pan`, `LongPress`, `Fling`, `Pinch`, `Rotation`, `ForceTouch`) or any composed gesture (`Race`, `Simultaneous`, `Exclusive`).
3297
3298**Info:**\
3299The `GestureDetector` determines whether to use Reanimated for processing provided gestures based on their callbacks. If a callback is a worklet, Reanimated tools are utilized, enabling synchronous gesture handling.
3300
3301Starting with Reanimated 2.3.0, Gesture Handler provides a StateManager in touch events, facilitating gesture state management.
3302
3303#### `userSelect` (Web only)
3304
3305This parameter specifies the `userSelect` property for the underlying view. Possible values include `"none"`, `"auto"`, or `"text"`. The default is set to `"none"`.
3306
3307#### `touchAction` (Web only)
3308
3309This parameter defines the `touchAction` property for the underlying view, supporting all CSS `touch-action` values such as `"none"` and `"pan-y"`. The default value is `"none"`.
3310
3311#### `enableContextMenu(value: boolean)` (Web only)
3312
3313Determines whether a context menu should be enabled after right-clicking on the underlying view. By default, this is set to `false`.
3314
3315### Remarks
3316
3317- **Gesture Recognition:**\
3318 Gesture Detector uses the first native view in its subtree for gesture recognition. If this view serves solely as a container for its children, it may be automatically collapsed. Consider the following example:
3319
3320 ```typescript
3321 export default function Example() {
3322 const tap = Gesture.Tap().onStart(() => {
3323 console.log('tap');
3324 });
3325
3326 return (
3327 <GestureDetector gesture={tap}>
3328 <FunctionalComponent>
3329 <View style={styles.box} />
3330 </FunctionalComponent>
3331 </GestureDetector>
3332 );
3333 }
3334
3335 function FunctionalComponent(props) {
3336 return <View collapsable={false}>{props.children}</View>;
3337 }
3338 ```
3339
3340 Removing the `collapsable` prop from the View would cause the gesture to malfunction, as it would be attached to a view absent in the hierarchy. Gesture Detector automatically adds this prop to its direct child but cannot do so for more complex view trees.
3341
3342- **Gesture Instance Usage:**\
3343 Using the same instance of a gesture across multiple Gesture Detectors is not feasible. Consider the following code:
3344
3345 ```typescript
3346 export default function Example() {
3347 const pan = Gesture.Pan();
3348
3349 return (
3350 <View>
3351 <GestureDetector gesture={pan}>
3352 <View>
3353 <GestureDetector gesture={pan}> {/* Avoid this! */}
3354 <View />
3355 </GestureDetector>
3356 </View>
3357 </GestureDetector>
3358 </View>
3359 );
3360 }
3361 ```
3362
3363 This example will result in an error because it attempts to use the same `Pan` instance in two different Gesture Detectors.
3364
3365## Buttons
3366
3367The Gesture Handler library offers native components designed to function as buttons. These components serve as alternatives to `TouchableHighlight` or `TouchableOpacity` from React Native's core library. The key advantages of using Gesture Handler's buttons include:
3368
3369- **Native Touch Recognition**: They recognize touches natively, ensuring a deterministic process.
3370- **High Performance on Android**: Enables rendering ripples efficiently with `TouchableNativeFeedback`, avoiding the lag caused by touch events needing to return to JavaScript before updating ripple effects—a common issue on older devices.
3371- **Optimized Interaction in Scrollable Containers**: Provides native and platform-specific default interactions for buttons within scrollable containers, where interaction is slightly delayed. This delay prevents premature button highlighting during flinging actions.
3372
3373These features enhance the user experience by ensuring smooth and responsive button interactions across different platforms and device capabilities.
3374
3375## Gesture
3376
3377`Gesture` is an object that facilitates the creation and composition of gestures.
3378
3379### Reference
3380
3381```typescript
3382import { GestureDetector, Gesture } from 'react-native-gesture-handler';
3383
3384function App() {
3385 const tap = Gesture.Tap();
3386
3387 return (
3388 <GestureDetector gesture={tap}>
3389 <Animated.View />
3390 </GestureDetector>
3391 );
3392}
3393```
3394
3395#### Gesture Methods
3396
3397- **`Gesture.Tap()`**: Creates a `TapGesture` instance with default configuration and no callbacks.
3398
3399- **`Gesture.Pan()`**: Generates a `PanGesture` instance with default settings and no callbacks.
3400
3401- **`Gesture.LongPress()`**: Produces a `LongPressGesture` instance with default configuration and no callbacks.
3402
3403- **`Gesture.Fling()`**: Forms a `FlingGesture` instance with default setup and no callbacks.
3404
3405- **`Gesture.Pinch()`**: Constructs a `PinchGesture` instance with default parameters and no callbacks.
3406
3407- **`Gesture.Rotation()`**: Establishes a `RotationGesture` instance with default configuration and no callbacks.
3408
3409- **`Gesture.Hover()`**: Creates a `HoverGesture` instance with default settings and no callbacks.
3410
3411- **`Gesture.ForceTouch()`**: Generates a `ForceTouchGesture` instance with default configuration and no callbacks.
3412
3413- **`Gesture.Manual()`**: Forms a `ManualGesture` instance with default setup and no callbacks.
3414
3415- **`Gesture.Native()`**: Produces a `NativeGesture` instance with default parameters and no callbacks.
3416
3417#### Gesture Composition
3418
3419- **`Gesture.Race(gesture1, gesture2, gesture3, ...)`**: Composes gestures such that only one can be active at any time. The first to activate cancels the others.
3420
3421- **`Gesture.Simultaneous(gesture1, gesture2, gesture3, ...)`**: Allows all provided gestures to become active simultaneously without cancelling each other.
3422
3423- **`Gesture.Exclusive(gesture1, gesture2, gesture3, ...)`**: Composes gestures where only one can be active at a time. The first has the highest priority, followed by subsequent ones in order. Useful for composing similar activation criteria gestures (e.g., single and double tap).
3424
3425### Remarks
3426
3427- To optimize performance, consider using `useMemo` to wrap gesture configurations. This reduces the workload for Gesture Handler during updates.
3428
3429```typescript
3430import React from "react"
3431
3432function App() {
3433 const gesture = React.useMemo(
3434 () =>
3435 Gesture.Tap().onStart(() => {
3436 console.log("Number of taps:", tapNumber + 1)
3437 setTapNumber((value) => value + 1)
3438 }),
3439 [tapNumber, setTapNumber]
3440 )
3441 // ...
3442}
3443```
3444
3445## Drawer Layout
3446
3447> **Caution:** This is a cross-platform alternative to React Native's `DrawerLayoutAndroid` component. It offers a compatible API and can be used on both Android and iOS platforms. For detailed usage of standard parameters, refer to the React Native documentation.
3448
3449### Usage:
3450
3451The `DrawerLayout` component is not exported by default from the `react-native-gesture-handler` package. To use it, import as follows:
3452
3453```typescript
3454import DrawerLayout from "react-native-gesture-handler/DrawerLayout"
3455```
3456
3457### Properties:
3458
3459In addition to standard parameters, `DrawerLayout` includes additional attributes for customization:
3460
3461#### `drawerType`
3462
3463- **Possible values:** `front`, `back`, or `slide` (default is `front`)
3464- **Description:**
3465 - `front`: The drawer slides in and out with the gesture, appearing on top of the content view.
3466 - `back`: The drawer appears behind the content view and can be revealed by pulling the content view to the side.
3467 - `slide`: The drawer seems attached to the side of the content view; both the content view and drawer follow the gesture.
3468
3469#### `edgeWidth`
3470
3471- **Type:** number
3472- **Description:** Defines how far from the edge of the content view the gesture should activate.
3473
3474#### `hideStatusBar`
3475
3476- **Type:** boolean
3477- **Description:** When set to `true`, the Drawer component uses the StatusBar API to hide the OS status bar when the drawer is pulled or open.
3478
3479#### `statusBarAnimation`
3480
3481- **Possible values:** `slide`, `none`, or `fade` (default is `slide`)
3482- **Description:** Used with `hideStatusBar` set to `true` to select the animation for hiding/showing the status bar. See StatusBar documentation for more details.
3483
3484#### `overlayColor`
3485
3486- **Type:** color (default: `"black"`)
3487- **Description:** Specifies a semi-transparent overlay color displayed on top of the content view when the drawer is open. The opacity is animated from 0% to 70%.
3488
3489#### `renderNavigationView`
3490
3491- **Type:** function
3492- **Description:** This attribute allows the function passed as `renderNavigationView` to take an Animated value indicating the progress of the drawer's opening/closing animation (progress value: 0 when closed, 1 when opened). It can be used to animate children components during this process.
3493
3494#### `onDrawerClose`
3495
3496- **Type:** function
3497- **Description:** Called when the drawer is closed.
3498
3499#### `onDrawerOpen`
3500
3501- **Type:** function
3502- **Description:** Called when the drawer is opened.
3503
3504#### `onDrawerSlide`
3505
3506- **Type:** function
3507- **Description:** Called during a drawer slide open from touch events. The progress of the drawer opening/closing (0 when closed, 1 when opened) is passed back.
3508
3509#### `onDrawerStateChanged`
3510
3511- **Type:** function
3512- **Arguments:**
3513 - `newState`: `DrawerState` - State of the `Drawer`. Possible values:
3514 - `Idle`
3515 - `Dragging`
3516 - `Settling`
3517 - `drawerWillShow`: boolean - Indicates if the drawer is about to open.
3518
3519#### `enableTrackpadTwoFingerGesture` (iOS only)
3520
3521- **Type:** boolean
3522- **Description:** Enables two-finger gestures on supported devices, such as iPads with trackpads. Without this enabled, a click + drag gesture is required; otherwise, swiping with two fingers will trigger the gesture.
3523
3524#### `children`
3525
3526- **Type:** component or function
3527- **Description:** The default child component rendered and wrapped by the drawer. It can also be a render function that takes an Animated value indicating the progress of the drawer's opening/closing animation (progress value: 0 when closed, 1 when opened), similar to `renderNavigationView`.
3528
3529#### `mouseButton(value: MouseButton)` (Web & Android only)
3530
3531- **Type:** enum
3532- **Description:** Allows users to choose which mouse button should trigger the handler. The `MouseButton` enum includes:
3533 - `LEFT`
3534 - `RIGHT`
3535 - `MIDDLE`
3536 - `BUTTON_4`
3537 - `BUTTON_5`
3538 - `ALL`
3539- **Usage:** Arguments can be combined using the `|` operator, e.g., `mouseButton(MouseButton.LEFT | MouseButton.RIGHT)`. Default is set to `MouseButton.LEFT`.
3540
3541#### `enableContextMenu(value: boolean)` (Web only)
3542
3543- **Type:** boolean
3544- **Description:** Specifies whether a context menu should be enabled after clicking on the underlying view with the right mouse button. Default value is `false`.
3545
3546### Methods:
3547
3548#### `openDrawer(options)`
3549
3550- **Description:** Can take an optional `options` parameter for customizing the open animation.
3551- **Options:**
3552 - `velocity`: number, initial velocity of the object attached to the spring (default: 0).
3553 - `speed`: number, controls speed of the animation (default: 12).
3554
3555#### `closeDrawer(options)`
3556
3557- **Description:** Can take an optional `options` parameter for customizing the close animation.
3558- **Options:**
3559 - `velocity`: number, initial velocity of the object attached to the spring (default: 0).
3560 - `speed`: number, controls speed of the animation (default: 12).
3561
3562### Example:
3563
3564See the drawer example from the GestureHandler Example App or view it directly on your phone by visiting our Expo demo.
3565
3566```typescript
3567class Drawerable extends Component {
3568 handleDrawerSlide = (status) => {
3569 // Outputs a value between 0 and 1
3570 console.log(status);
3571 };
3572
3573 renderDrawer = () => {
3574 return (
3575 <View>
3576 <Text>I am in the drawer!</Text>
3577 </View>
3578 );
3579 };
3580
3581 render() {
3582 return (
3583 <View style={{ flex: 1 }}>
3584 <DrawerLayout
3585 drawerWidth={200}
3586 drawerPosition={DrawerLayout.positions.Right}
3587 drawerType="front"
3588 drawerBackgroundColor="#ddd"
3589 renderNavigationView={this.renderDrawer}
3590 onDrawerSlide={this.handleDrawerSlide}>
3591 <View>
3592 <Text>Hello, it's me</Text>
3593 </View>
3594 </DrawerLayout>
3595 </View>
3596 );
3597 }
3598}
3599```
3600
3601## Gesture composition & interactions
3602
3603In RNGH2, composing gestures has been simplified compared to previous versions. There is no longer a need to create a reference for each gesture that depends on another one. Instead, you can utilize the Race, Simultaneous, and Exclusive methods provided by the Gesture object.
3604
3605### Methods for Composing Gestures
3606
3607- **Race**: This method allows multiple gestures to compete against each other. The first gesture to complete will be recognized.
3608
3609- **Simultaneous**: With this method, multiple gestures are required to occur at the same time in order to trigger an action.
3610
3611- **Exclusive**: This method ensures that only one specific gesture can be recognized at a time, preventing overlap with others.
3612
3613These methods facilitate more intuitive and flexible gesture interactions within your application.
3614
3615## Manual gestures
3616
3617RNGH2 introduces manual gestures and touch events, allowing for custom gesture tracking. This guide demonstrates creating a simple gesture that tracks all pointers on the screen.
3618
3619### Step 1: Define Pointer Information
3620
3621First, define an interface to store pointer information, including visibility and position:
3622
3623```typescript
3624interface Pointer {
3625 visible: boolean
3626 x: number
3627 y: number
3628}
3629```
3630
3631### Step 2: Create a Pointer Element Component
3632
3633Create a component that displays the pointer's location. It uses shared values for pointer data and gesture activation status. The pointer is represented by a ball, changing color and size based on its state:
3634
3635```typescript
3636import { StyleSheet } from 'react-native';
3637import Animated, {
3638 useAnimatedStyle,
3639 useSharedValue,
3640} from 'react-native-reanimated';
3641
3642function PointerElement(props: {
3643 pointer: Animated.SharedValue<Pointer>,
3644 active: Animated.SharedValue<boolean>,
3645}) {
3646 const animatedStyle = useAnimatedStyle(() => ({
3647 transform: [
3648 { translateX: props.pointer.value.x },
3649 { translateY: props.pointer.value.y },
3650 {
3651 scale:
3652 (props.pointer.value.visible ? 1 : 0) *
3653 (props.active.value ? 1.3 : 1),
3654 },
3655 ],
3656 backgroundColor: props.active.value ? 'red' : 'blue',
3657 }));
3658
3659 return <Animated.View style={[styles.pointer, animatedStyle]} />;
3660}
3661
3662const styles = StyleSheet.create({
3663 pointer: {
3664 width: 60,
3665 height: 60,
3666 borderRadius: 30,
3667 backgroundColor: 'red',
3668 position: 'absolute',
3669 marginStart: -30,
3670 marginTop: -30,
3671 },
3672});
3673```
3674
3675### Step 3: Handle Gesture and Draw Pointers
3676
3677Create a component to manage the gesture, storing pointer data in an array. Render pointers within an `Animated.View`:
3678
3679```typescript
3680import { Gesture, GestureDetector } from 'react-native-gesture-handler';
3681
3682export default function Example() {
3683 const trackedPointers: Animated.SharedValue<Pointer>[] = [];
3684 const active = useSharedValue(false);
3685
3686 for (let i = 0; i < 12; i++) {
3687 trackedPointers[i] =
3688 useSharedValue <
3689 Pointer >
3690 {
3691 visible: false,
3692 x: 0,
3693 y: 0,
3694 };
3695 }
3696
3697 const gesture = Gesture.Manual();
3698
3699 return (
3700 <GestureDetector gesture={gesture}>
3701 <Animated.View style={{ flex: 1 }}>
3702 {trackedPointers.map((pointer, index) => (
3703 <PointerElement pointer={pointer} active={active} key={index} />
3704 ))}
3705 </Animated.View>
3706 </GestureDetector>
3707 );
3708}
3709```
3710
3711### Step 4: Implement onTouchesDown
3712
3713Set up the gesture to track pointers on touch down. Activate the gesture if there are at least two touches:
3714
3715```typescript
3716const gesture = Gesture.Manual().onTouchesDown((e, manager) => {
3717 for (const touch of e.changedTouches) {
3718 trackedPointers[touch.id].value = {
3719 visible: true,
3720 x: touch.x,
3721 y: touch.y,
3722 }
3723 }
3724
3725 if (e.numberOfTouches >= 2) {
3726 manager.activate()
3727 }
3728})
3729```
3730
3731### Step 5: Handle onTouchesMove
3732
3733Update pointer positions during movement:
3734
3735```typescript
3736const gesture = Gesture.Manual()
3737 ...
3738 .onTouchesMove((e, _manager) => {
3739 for (const touch of e.changedTouches) {
3740 trackedPointers[touch.id].value = {
3741 visible: true,
3742 x: touch.x,
3743 y: touch.y,
3744 };
3745 }
3746 })
3747```
3748
3749### Step 6: Implement onTouchesUp
3750
3751Hide pointers on lift and end the gesture if no touches remain:
3752
3753```typescript
3754const gesture = Gesture.Manual()
3755 ...
3756 .onTouchesUp((e, manager) => {
3757 for (const touch of e.changedTouches) {
3758 trackedPointers[touch.id].value = {
3759 visible: false,
3760 x: touch.x,
3761 y: touch.y,
3762 };
3763 }
3764
3765 if (e.numberOfTouches === 0) {
3766 manager.end();
3767 }
3768 })
3769```
3770
3771### Step 7: Manage Gesture Activation
3772
3773Control gesture activation state using shared values:
3774
3775```typescript
3776const gesture = Gesture.Manual()
3777 ...
3778 .onStart(() => {
3779 active.value = true;
3780 })
3781 .onEnd(() => {
3782 active.value = false;
3783 });
3784```
3785
3786Manual gestures offer powerful customization, enabling complex interactions. Additionally, existing gestures can be modified with `manualActivation` to control activation behavior, such as implementing drag after a long press by setting `manualActivation` on a `PanGesture`.
3787
3788## Pressable
3789
3790### Overview
3791
3792The `Pressable` component is a versatile drop-in replacement for the standard `Pressable` component. It detects various stages of tap, press, and hover interactions on its children.
3793
3794#### Importing
3795
3796To use `Pressable`, import it as follows:
3797
3798```typescript
3799import { Pressable } from "react-native-gesture-handler"
3800```
3801
3802### Properties
3803
3804|Property|Description|
3805|-|-|
3806|`children`|Accepts either children or a render function that receives a boolean indicating if the component is currently pressed.|
3807|`style`|Can be view styles or a function receiving a boolean reflecting the press state and returning view styles.|
3808|`onPress`|Triggered after `onPressOut` when a single tap gesture is detected.|
3809|`onPressIn`|Called before `onPress` when a touch is engaged.|
3810|`onPressOut`|Called before `onPress` when a touch is released.|
3811|`onLongPress`|Triggered immediately after the pointer has been down for at least `delayLongPress` milliseconds (default: 500 ms). After this, `onPressOut` will be called upon pointer lift and `onPress` won't trigger.|
3812|`cancelable`|Determines if a press gesture can be interrupted by a parent gesture like scrolling. Defaults to `true`.|
3813|`onHoverIn` (Web only)|Called when the pointer hovers over the element.|
3814|`onHoverOut` (Web only)|Triggered when the pointer stops hovering over the element.|
3815|`delayHoverIn` (Web only)|Duration to wait after hover in before calling `onHoverIn`.|
3816|`delayHoverOut` (Web only)|Duration to wait after hover out before calling `onHoverOut`.|
3817|`delayLongPress`|Time in milliseconds from `onPressIn` before `onLongPress` is called.|
3818|`disabled`|Disables the `Pressable` behavior if set to true.|
3819|`hitSlop` (Android & iOS only)|Additional distance outside of the view where a press is detected and `onPressIn` is triggered. Accepts `number` or `Rect`.|
3820|`pressRetentionOffset` (Android & iOS only)|Extra distance outside of the view (or `hitSlop` if present) to consider a touch as a press before `onPressOut` is triggered. Accepts `number` or `Rect`.|
3821|`android_disableSound` (Android only)|If true, prevents system sound on touch.|
3822|`android_ripple` (Android only)|Enables the Android ripple effect and configures its color, radius, etc. Accepts `RippleConfig`.|
3823|`testOnly_pressed`|Used for documentation or testing purposes (e.g., snapshot testing).|
3824|`unstable_pressDelay`|Duration in milliseconds to wait after press down before calling `onPressIn`.|
3825
3826### Example
3827
3828Below is an example demonstrating the use of `Pressable`:
3829
3830```typescript
3831import { View, Text, StyleSheet } from 'react-native';
3832import { Pressable } from 'react-native-gesture-handler';
3833
3834export default function Example() {
3835 return (
3836 <Pressable
3837 style={({ pressed }) => (pressed ? styles.highlight : styles.pressable)}
3838 hitSlop={20}
3839 pressRetentionOffset={20}>
3840 <View style={styles.textWrapper}>
3841 <Text style={styles.text}>Pressable!</Text>
3842 </View>
3843 </Pressable>
3844 );
3845}
3846
3847const styles = StyleSheet.create({
3848 pressable: {
3849 width: 120,
3850 height: 120,
3851 backgroundColor: 'mediumpurple',
3852 borderWidth: StyleSheet.hairlineWidth,
3853 },
3854 highlight: {
3855 width: 120,
3856 height: 120,
3857 backgroundColor: 'red',
3858 borderWidth: StyleSheet.hairlineWidth,
3859 },
3860 textWrapper: {
3861 flex: 1,
3862 justifyContent: 'center',
3863 alignItems: 'center',
3864 },
3865 text: {
3866 color: 'black',
3867 },
3868});
3869```
3870
3871## Gesture composition & interactions
3872
3873Composing gestures in RNGH2 is straightforward. You don't need to create a ref for each gesture that depends on another one. Instead, use `Race`, `Simultaneous`, and `Exclusive` methods provided by the `Gesture` object.
3874
3875### Race
3876
3877The `Race` method allows only one of the provided gestures to become active at any time. The first gesture to activate will cancel the others. It accepts a variable number of arguments and is equivalent to having multiple gesture handlers without defining `simultaneousHandlers` or `waitFor` props.
3878
3879#### Example: Draggable Component with Long Press
3880
3881Consider a component that should be draggable, but also show additional options on long press. You can use `Race` to ensure the component doesn't move after a long press activates:
3882
3883```typescript
3884import { GestureDetector, Gesture } from 'react-native-gesture-handler';
3885import Animated, {
3886 useSharedValue,
3887 useAnimatedStyle,
3888 withTiming,
3889} from 'react-native-reanimated';
3890
3891function App() {
3892 const offset = useSharedValue({ x: 0, y: 0 });
3893 const start = useSharedValue({ x: 0, y: 0 });
3894 const popupPosition = useSharedValue({ x: 0, y: 0 });
3895 const popupAlpha = useSharedValue(0);
3896
3897 const animatedStyles = useAnimatedStyle(() => ({
3898 transform: [
3899 { translateX: offset.value.x },
3900 { translateY: offset.value.y },
3901 ],
3902 }));
3903
3904 const animatedPopupStyles = useAnimatedStyle(() => ({
3905 transform: [
3906 { translateX: popupPosition.value.x },
3907 { translateY: popupPosition.value.y },
3908 ],
3909 opacity: popupAlpha.value,
3910 }));
3911
3912 const dragGesture = Gesture.Pan()
3913 .onStart((_e) => {
3914 popupAlpha.value = withTiming(0);
3915 })
3916 .onUpdate((e) => {
3917 offset.value = {
3918 x: e.translationX + start.value.x,
3919 y: e.translationY + start.value.y,
3920 };
3921 })
3922 .onEnd(() => {
3923 start.value = { x: offset.value.x, y: offset.value.y };
3924 });
3925
3926 const longPressGesture = Gesture.LongPress().onStart((_event) => {
3927 popupPosition.value = { x: offset.value.x, y: offset.value.y };
3928 popupAlpha.value = withTiming(1);
3929 });
3930
3931 const composed = Gesture.Race(dragGesture, longPressGesture);
3932
3933 return (
3934 <Animated.View>
3935 <Popup style={animatedPopupStyles} />
3936 <GestureDetector gesture={composed}>
3937 <Component style={animatedStyles} />
3938 </GestureDetector>
3939 </Animated.View>
3940 );
3941}
3942```
3943
3944### Simultaneous
3945
3946The `Simultaneous` method allows all provided gestures to activate at the same time. Activation of one does not cancel the others, similar to having gesture handlers with each set to `simultaneousHandlers`.
3947
3948#### Example: Gallery App with Zoom, Rotate, and Pan
3949
3950For a gallery app where users can zoom, rotate, and pan photos simultaneously:
3951
3952```typescript
3953import { GestureDetector, Gesture } from 'react-native-gesture-handler';
3954import Animated, {
3955 useSharedValue,
3956 useAnimatedStyle,
3957} from 'react-native-reanimated';
3958
3959function App() {
3960 const offset = useSharedValue({ x: 0, y: 0 });
3961 const start = useSharedValue({ x: 0, y: 0 });
3962 const scale = useSharedValue(1);
3963 const savedScale = useSharedValue(1);
3964 const rotation = useSharedValue(0);
3965 const savedRotation = useSharedValue(0);
3966
3967 const animatedStyles = useAnimatedStyle(() => ({
3968 transform: [
3969 { translateX: offset.value.x },
3970 { translateY: offset.value.y },
3971 { scale: scale.value },
3972 { rotateZ: `${rotation.value}rad` },
3973 ],
3974 }));
3975
3976 const dragGesture = Gesture.Pan()
3977 .averageTouches(true)
3978 .onUpdate((e) => {
3979 offset.value = {
3980 x: e.translationX + start.value.x,
3981 y: e.translationY + start.value.y,
3982 };
3983 })
3984 .onEnd(() => {
3985 start.value = { x: offset.value.x, y: offset.value.y };
3986 });
3987
3988 const zoomGesture = Gesture.Pinch()
3989 .onUpdate((event) => {
3990 scale.value = savedScale.value * event.scale;
3991 })
3992 .onEnd(() => {
3993 savedScale.value = scale.value;
3994 });
3995
3996 const rotateGesture = Gesture.Rotation()
3997 .onUpdate((event) => {
3998 rotation.value = savedRotation.value + event.rotation;
3999 })
4000 .onEnd(() => {
4001 savedRotation.value = rotation.value;
4002 });
4003
4004 const composed = Gesture.Simultaneous(
4005 dragGesture,
4006 Gesture.Simultaneous(zoomGesture, rotateGesture)
4007 );
4008
4009 return (
4010 <Animated.View>
4011 <GestureDetector gesture={composed}>
4012 <Photo style={animatedStyles} />
4013 </GestureDetector>
4014 </Animated.View>
4015 );
4016}
4017```
4018
4019### Exclusive
4020
4021The `Exclusive` method allows only one of the provided gestures to become active at a time, with priority given in order. It is equivalent to having gesture handlers where each subsequent handler has its `waitFor` prop set to all preceding ones.
4022
4023#### Example: Single Tap and Double Tap
4024
4025To create a component that responds to both single tap and double tap:
4026
4027```typescript
4028import { GestureDetector, Gesture } from 'react-native-gesture-handler';
4029
4030function App() {
4031 const singleTap = Gesture.Tap().onEnd((_event, success) => {
4032 if (success) {
4033 console.log('single tap!');
4034 }
4035 });
4036
4037 const doubleTap = Gesture.Tap()
4038 .numberOfTaps(2)
4039 .onEnd((_event, success) => {
4040 if (success) {
4041 console.log('double tap!');
4042 }
4043 });
4044
4045 const composed = Gesture.Exclusive(singleTap, doubleTap);
4046
4047 return (
4048 <GestureDetector gesture={composed}>
4049 <Component />
4050 </GestureDetector>
4051 );
4052}
4053```
4054
4055### Cross-Component Gesture Interactions
4056
4057#### blocksExternalGesture
4058
4059`blocksExternalGesture` is used to make a component wait for gestures from other components. It's useful in lists where the `ScrollView` needs to wait for gestures on its children.
4060
4061```typescript
4062import React, { useRef } from 'react';
4063import { StyleSheet } from 'react-native';
4064import {
4065 GestureDetector,
4066 Gesture,
4067 GestureHandlerRootView,
4068 ScrollView,
4069} from 'react-native-gesture-handler';
4070import Animated, {
4071 useSharedValue,
4072 useAnimatedStyle,
4073 withTiming,
4074} from 'react-native-reanimated';
4075
4076const ITEMS = ['red', 'green', 'blue', 'yellow'];
4077
4078function Item({ backgroundColor, scrollRef }) {
4079 const scale = useSharedValue(1);
4080 const zIndex = useSharedValue(1);
4081
4082 const pinch = Gesture.Pinch()
4083 .blocksExternalGesture(scrollRef)
4084 .onBegin(() => {
4085 zIndex.value = 100;
4086 })
4087 .onChange((e) => {
4088 scale.value *= e.scaleChange;
4089 })
4090 .onFinalize(() => {
4091 scale.value = withTiming(1, undefined, (finished) => {
4092 if (finished) {
4093 zIndex.value = 1;
4094 }
4095 });
4096 });
4097
4098 const animatedStyles = useAnimatedStyle(() => ({
4099 transform: [{ scale: scale.value }],
4100 zIndex: zIndex.value,
4101 }));
4102
4103 return (
4104 <GestureDetector gesture={pinch}>
4105 <Animated.View
4106 style={[
4107 { backgroundColor: backgroundColor },
4108 styles.item,
4109 animatedStyles,
4110 ]}
4111 />
4112 </GestureDetector>
4113 );
4114}
4115
4116export default function Example() {
4117 const scrollRef = useRef();
4118
4119 return (
4120 <GestureHandlerRootView style={styles.container}>
4121 <ScrollView style={styles.container} ref={scrollRef}>
4122 {ITEMS.map((item) => (
4123 <Item backgroundColor={item} key={item} scrollRef={scrollRef} />
4124 ))}
4125 </ScrollView>
4126 </GestureHandlerRootView>
4127 );
4128}
4129
4130const styles = StyleSheet.create({
4131 container: {
4132 flex: 1,
4133 },
4134 item: {
4135 flex: 1,
4136 aspectRatio: 1,
4137 },
4138});
4139```
4140
4141#### simultaneousWithExternalGesture
4142
4143`simultaneousWithExternalGesture` allows gestures across different components to be recognized simultaneously.
4144
4145```typescript
4146import React from 'react';
4147import { View, StyleSheet } from 'react-native';
4148import {
4149 GestureDetector,
4150 Gesture,
4151 GestureHandlerRootView,
4152} from 'react-native-gesture-handler';
4153
4154export default function Example() {
4155 const innerTap = Gesture.Tap().onStart(() => {
4156 console.log('inner tap');
4157 });
4158
4159 const outerTap = Gesture.Tap()
4160 .onStart(() => {
4161 console.log('outer tap');
4162 })
4163 .simultaneousWithExternalGesture(innerTap);
4164
4165 return (
4166 <GestureHandlerRootView style={styles.container}>
4167 <GestureDetector gesture={outerTap}>
4168 <View style={styles.outer}>
4169 <GestureDetector gesture={innerTap}>
4170 <View style={styles.inner} />
4171 </GestureDetector>
4172 </View>
4173 </GestureDetector>
4174 </GestureHandlerRootView>
4175 );
4176}
4177
4178const styles = StyleSheet.create({
4179 container: {
4180 flex: 1,
4181 alignItems: 'center',
4182 justifyContent: 'center',
4183 },
4184 outer: {
4185 width: 250,
4186 height: 250,
4187 backgroundColor: 'lightblue',
4188 },
4189 inner: {
4190 width: 100,
4191 height: 100,
4192 backgroundColor: 'blue',
4193 alignSelf: 'center',
4194 },
4195});
4196```
4197
4198## Reanimated Drawer Layout
4199
4200A cross-platform alternative to React Native's `DrawerLayoutAndroid`. For standard parameter usage, refer to the React Native documentation.
4201
4202### Usage:
4203
4204Import as follows:
4205
4206```typescript
4207import ReanimatedDrawerLayout from "react-native-gesture-handler/ReanimatedDrawerLayout"
4208```
4209
4210### Properties:
4211
4212#### `drawerType`
4213
4214Defines how the drawer is displayed. Accepts values from the `DrawerPosition` enum. Defaults to `FRONT`.
4215
4216- **`FRONT`**: Drawer appears above the content view.
4217- **`BACK`**: Drawer appears below the content view, revealed by sliding away the content view.
4218- **`SLIDE`**: Drawer slides with the content view.
4219
4220|`FRONT`|`BACK`|`SLIDE`|
4221|-|-|-|
4222
4223#### `edgeWidth`
4224
4225Specifies the width of the invisible, draggable area on the edge of the content view to open the drawer.
4226
4227#### `hideStatusBar`
4228
4229A boolean value. When set to `true`, hides the OS status bar when the drawer is dragged or idle in the `open` position using the StatusBar API.
4230
4231#### `statusBarAnimation`
4232
4233Defines the animation for hiding the status bar, with possible values: `slide`, `none`, or `fade`. Defaults to `slide`. Used with `hideStatusBar`.
4234
4235#### `overlayColor`
4236
4237Sets the background overlay color on top of the content window when the drawer is open. The opacity animates from 0% to 100% as the drawer transitions from closed to open. Defaults to `rgba(0, 0, 0, 0.7)`.
4238
4239#### `renderNavigationView`
4240
4241A function renderer for the drawer component, provided with a `progress` parameter:
4242
4243- **`progress`**: A `SharedValue` indicating the progress of the drawer's opening/closing animation (0 when closed, 1 when open).
4244
4245#### `onDrawerClose`
4246
4247Function called when the drawer is closed.
4248
4249#### `onDrawerOpen`
4250
4251Function called when the drawer is opened.
4252
4253#### `onDrawerSlide`
4254
4255Function called during drawer movement or animation, provided with a `progress` parameter:
4256
4257- **`progress`**: A `SharedValue` indicating the progress of the drawer's opening/closing animation (0 when closed, 1 when open).
4258
4259#### `onDrawerStateChanged`
4260
4261Function called when the drawer's status changes. Takes two arguments:
4262
4263- **`newState`**: Interaction state of the drawer (`DrawerState.IDLE`, `DrawerState.DRAGGING`, or `DrawerState.SETTLING`).
4264- **`drawerWillShow`**: `true` if the drawer is animating to open, otherwise `false`.
4265
4266#### `enableTrackpadTwoFingerGesture` (iOS only)
4267
4268Enables two-finger gestures on supported devices. Without this, a click + drag gesture is required.
4269
4270#### `children`
4271
4272Either a component rendered in the content view or a function provided with a `progress` parameter:
4273
4274- **`progress`**: A `SharedValue` indicating the progress of the drawer's opening/closing animation (0 when closed, 1 when open).
4275
4276#### `mouseButton(value: MouseButton)` (Web & Android only)
4277
4278Allows selection of mouse button for gesture handling. The enum `MouseButton` includes:
4279
4280- `LEFT`
4281- `RIGHT`
4282- `MIDDLE`
4283- `BUTTON_4`
4284- `BUTTON_5`
4285- `ALL`
4286
4287Values can be combined using the `|` operator, defaulting to `MouseButton.LEFT`.
4288
4289#### `enableContextMenu(value: boolean)` (Web only)
4290
4291Specifies if a context menu should appear after right-clicking on the underlying view. Defaults to `false`.
4292
4293### Methods:
4294
4295#### `openDrawer(options)`
4296
4297Opens the drawer with optional parameters:
4298
4299- **`initialVelocity`**: Initial velocity of the spring object, default is `0`.
4300- **`animationSpeed`**: Controls animation speed, default is `1`.
4301
4302#### `closeDrawer(options)`
4303
4304Closes the drawer with optional parameters:
4305
4306- **`initialVelocity`**: Initial velocity of the spring object, default is `0`.
4307- **`animationSpeed`**: Controls animation speed, default is `1`.
4308
4309### Example:
4310
4311```typescript
4312import React, { useRef } from 'react';
4313import { StyleSheet, Text, View } from 'react-native';
4314import { Gesture, GestureDetector } from 'react-native-gesture-handler';
4315
4316import ReanimatedDrawerLayout, {
4317 DrawerType,
4318 DrawerPosition,
4319 DrawerLayoutMethods,
4320} from 'react-native-gesture-handler/ReanimatedDrawerLayout';
4321
4322const DrawerPage = () => (
4323 <View style={styles.drawerContainer}>
4324 <Text>Lorem ipsum</Text>
4325 </View>
4326);
4327
4328export default function ReanimatedDrawerExample() {
4329 const drawerRef = useRef<DrawerLayoutMethods>(null);
4330 const tapGesture = Gesture.Tap()
4331 .runOnJS(true)
4332 .onStart(() => drawerRef.current?.openDrawer());
4333
4334 return (
4335 <ReanimatedDrawerLayout
4336 ref={drawerRef}
4337 renderNavigationView={() => <DrawerPage />}
4338 drawerPosition={DrawerPosition.LEFT}
4339 drawerType={DrawerType.FRONT}>
4340 <View style={styles.innerContainer}>
4341 <GestureDetector gesture={tapGesture}>
4342 <View style={styles.box}>
4343 <Text>Open drawer</Text>
4344 </View>
4345 </GestureDetector>
4346 </View>
4347 </ReanimatedDrawerLayout>
4348 );
4349}
4350
4351const styles = StyleSheet.create({
4352 drawerContainer: {
4353 flex: 1,
4354 justifyContent: 'center',
4355 alignItems: 'center',
4356 backgroundColor: 'pink',
4357 },
4358 innerContainer: {
4359 flex: 1,
4360 backgroundColor: 'white',
4361 alignItems: 'center',
4362 justifyContent: 'center',
4363 gap: 20,
4364 },
4365 box: {
4366 padding: 20,
4367 backgroundColor: 'pink',
4368 },
4369});
4370```
4371
4372## Introduction
4373
4374Gesture Handler offers a declarative API that taps into the native platform's touch and gesture systems, providing an alternative to React Native's built-in Gesture Responder System. By leveraging native touch handling, it addresses performance limitations inherent in the Gesture Responder System while offering enhanced control over native components capable of managing gestures independently. For further insights, consider watching a talk by Krzysztof Magiera that delves into issues with the responder system.
4375
4376The primary advantages of using React Native Gesture Handler include:
4377
4378- Utilizing the platform's native touch handling for gesture recognition (e.g., pinch, rotation, pan).
4379- Defining relationships between gestures to prevent conflicts among gestures and native components.
4380- Mechanisms for employing touchable components that operate on a native thread while adhering to default platform behaviors; for instance, delaying the pressed state in scrollable components to avoid highlighting during flinging.
4381- Seamless integration with `react-native-reanimated` for processing touch events on the UI thread.
4382- Support for various input devices such as touch screens, pens, and mice.
4383- Capability to incorporate any native component into Gesture Handler's touch system, allowing it to function alongside custom gestures.
4384
4385**Info:** It is recommended to use Reanimated for implementing gesture-driven animations with Gesture Handler. Its advanced features heavily depend on worklets and the UI runtime provided by Reanimated.
4386
4387### Learning Resources
4388
4389#### Apps
4390
4391- **Gesture Handler Example App**: The official showcase app for Gesture Handler.
4392
4393#### Talks and Workshops
4394
4395- **Declarative Future of Gestures and Animations in React Native** by Krzysztof Magiera: This talk explains the motivation behind creating the gesture handler library, along with an introduction to react-native-reanimated and its use cases with Gesture Handler.
4396
4397- **React Native Workshop with Expo Team @ReactEurope 2018** by Brent Vatne: A comprehensive workshop detailing Gesture Handler and offering exercises for beginners.
4398
4399- **Living in an Async World of React Native** by Krzysztof Magiera: This talk highlights issues with React Native's touch system that Gesture Handler aims to resolve, explaining the motivation behind its development.
4400
4401- **React Native Touch & Gesture** by Krzysztof Magiera: A presentation on the limitations of the JS responder system and core features of Gesture Handler.
4402
4403### Contributing
4404
4405If you're interested in contributing or supporting this project, feel free to reach out to any team member via Twitter or Bluesky (links below). All pull requests are welcome; however, please discuss with us before embarking on significant projects.
4406
4407To start contributing code:
4408
4409- Review open issues and tackle one that seems manageable.
4410- Update documentation when you find information unclear, missing, or outdated.
4411
4412Contributions aren't limited to code. Consider responding to issues if you can offer assistance.
4413
4414### Community
4415
4416We are proud of the community built around this package and appreciate all forms of help, whether it's a pull request, issue report, comments on existing issues, or sharing demos and tutorials on social media. If you've created something with this library that you'd like to share, please contact us—we're eager to promote your work.
4417
4418#### Gesture Handler Team 🚀
4419
4420- Jakub Piasecki
4421- Michał Bert
4422- Ignacy Łątka
4423- Krzysztof Magiera
4424
4425#### Sponsors
4426
4427We are grateful for our sponsors who enable the development of this library and contribute to enhancing the React Native ecosystem. Special thanks to all our supporters!
4428
4429## Troubleshooting
4430
4431### Seeking Help with Issues
4432
4433Thank you for trying out this library! If you encounter any issues, here's how to get assistance:
4434
44351. **Check GitHub Issues**: Look through existing issues on GitHub; someone might have already resolved a similar problem.
44361. **Report New Issues**: Follow our guidelines if your issue is new or unresolved by previous solutions.
44371. **Join Expo Developers Discord**: Engage with the community for support and discussions.
44381. **Read Source Code**: For in-depth understanding, reviewing the source code can provide insights into potential bugs.
44391. **Contribute Solutions**: If you find a fix, consider contributing to improve documentation or library functionality.
4440
4441### Reporting Issues
4442
4443This library is maintained by a small team. Here’s how you can help us address issues efficiently:
4444
4445- Provide complete issue descriptions, including environment details (library version, RN version, device OS).
4446- Share an example app that reproduces the issue via gist, snack, or GitHub.
4447- Describe steps to reproduce the issue in your repro app.
4448- Minimize dependencies and isolate the problem in a minimal repro app.
4449- Note any findings about the root cause of the issue.
4450
4451**Note**: Avoid commenting on closed issues. If a solution doesn't work for you, open a new issue with all necessary details and reference previous solutions.
4452
4453### Feature Clarifications
4454
4455- **Gesture Prop Changes**: The `enabled` prop only affects gestures at their start (when a finger touches the screen).
4456- **Native Gesture Behavior**: May differ from standard due to platform-specific integrations.
4457- **Touchables Styling**: Requires separate styling for `style` and `containerStyle` props.
4458- **Gesture Composition**: All composed gestures must be attached to the same `GestureHandlerRootView`.
4459
4460#### Multiple Instances of Gesture Handler
4461
4462This error occurs when multiple instances of Gesture Handler are detected, often due to dependencies installing it in their own `node_modules`. To resolve:
4463
44641. Identify libraries using Gesture Handler:
4465
4466 - Use `npm ls react-native-gesture-handler` or `yarn why react-native-gesture-handler`.
4467
44681. Ensure a single version is used by adding resolutions (Yarn) or overrides (NPM):
4469
4470 **For Yarn:**
4471
4472 ```json
4473 "resolutions": {
4474 "react-native-gesture-handler": "<Gesture Handler version>"
4475 }
4476 ```
4477
4478 **For NPM:**
4479
4480 ```json
4481 "overrides": {
4482 "react-native-gesture-handler": "<Gesture Handler version>"
4483 }
4484 ```
4485
44861. Reinstall dependencies:
4487 - Run `yarn` or `npm install`.
4488
4489#### Automatic Workletization of Gesture Callbacks
4490
4491Reanimated's Babel plugin automatically marks gesture callbacks as worklets if defined in a single chain, eliminating the need for `'worklet';` directives:
4492
4493```typescript
4494const gesture = Gesture.Tap().onBegin(() => {
4495 console.log(_WORKLET)
4496})
4497```
4498
4499For callbacks not in a single chain, add `'worklet';` at the start:
4500
4501```typescript
4502const callback = () => {
4503 "worklet"
4504 console.log(_WORKLET)
4505}
4506const gesture = Gesture.Tap().onBegin(callback)
4507```
4508
4509This ensures proper workletization for asynchronous operations within gestures.
4510
4511## Tap gesture
4512
4513A tap gesture recognizes one or multiple taps. It detects brief touches on the screen by fingers, which must remain relatively stationary from their initial positions. You can configure tap gestures to recognize single, double, or triple taps based on specific requirements such as `minPointers`, `numberOfTaps`, `maxDist`, `maxDuration`, and `maxDelayMs`.
4514
4515### Example
4516
4517```typescript
4518import { View, StyleSheet } from 'react-native';
4519import { Gesture, GestureDetector } from 'react-native-gesture-handler';
4520
4521export default function App() {
4522 const singleTap = Gesture.Tap()
4523 .maxDuration(250)
4524 .onStart(() => {
4525 console.log('Single tap!');
4526 });
4527
4528 const doubleTap = Gesture.Tap()
4529 .maxDuration(250)
4530 .numberOfTaps(2)
4531 .onStart(() => {
4532 console.log('Double tap!');
4533 });
4534
4535 return (
4536 <GestureDetector gesture={Gesture.Exclusive(doubleTap, singleTap)}>
4537 <View style={styles.box} />
4538 </GestureDetector>
4539 );
4540}
4541
4542const styles = StyleSheet.create({
4543 box: {
4544 height: 120,
4545 width: 120,
4546 backgroundColor: '#b58df1',
4547 borderRadius: 20,
4548 marginBottom: 30,
4549 },
4550});
4551```
4552
4553### Configuration
4554
4555#### Properties Specific to `TapGesture`:
4556
4557- **minPointers(value: number)**\
4558 Minimum number of fingers required for gesture activation. Default is 1.
4559
4560- **maxDuration(value: number)**\
4561 Maximum time in milliseconds for a finger release after touch. Default is 500 ms.
4562
4563- **maxDelay(value: number)**\
4564 Maximum delay in milliseconds before the next tap if multiple taps are needed. Default is 500 ms.
4565
4566- **numberOfTaps(value: number)**\
4567 Number of taps required to activate the gesture. Default is 1.
4568
4569- **maxDeltaX(value: number)**\
4570 Maximum distance allowed along the X-axis during a tap. Exceeding this distance will cause the gesture to fail.
4571
4572- **maxDeltaY(value: number)**\
4573 Maximum distance allowed along the Y-axis during a tap. Exceeding this distance will cause the gesture to fail.
4574
4575- **maxDistance(value: number)**\
4576 Maximum distance allowed in any direction during a tap. Exceeding this distance will cause the gesture to fail.
4577
4578- **mouseButton(value: MouseButton) (Web & Android only)**\
4579 Specifies which mouse button should trigger the handler. Options include `LEFT`, `RIGHT`, `MIDDLE`, `BUTTON_4`, `BUTTON_5`, and `ALL`. Default is `MouseButton.LEFT`.
4580
4581#### Properties Common to All Gestures:
4582
4583- **enabled(value: boolean)**\
4584 Determines if the gesture handler analyzes touch events. Default is `true`.
4585
4586- **shouldCancelWhenOutside(value: boolean)**\
4587 Cancels or fails recognition when a finger leaves the view area. Defaults vary by gesture type.
4588
4589- **hitSlop(settings)**\
4590 Controls the active area for gesture recognition, allowing adjustments to each boundary side or overall dimensions.
4591
4592- **withRef(ref)**\
4593 Sets a reference to the gesture object for interoperability with older APIs.
4594
4595- **withTestId(testID)**\
4596 Assigns a `testID` property for querying in tests.
4597
4598- **cancelsTouchesInView(value) (iOS only)**\
4599 Cancels touches on native UI components when active. Default is `true`.
4600
4601- **runOnJS(value: boolean)**\
4602 Determines if callbacks run on the JS thread instead of the UI thread. Defaults to `false`.
4603
4604- **simultaneousWithExternalGesture(otherGesture1, otherGesture2, ...)**\
4605 Marks gestures for simultaneous recognition without composing them.
4606
4607- **requireExternalGestureToFail(otherGesture1, otherGesture2, ...)**\
4608 Requires another gesture to fail before activation.
4609
4610- **blocksExternalGesture(otherGesture1, otherGesture2, ...)**\
4611 Delays activation of other gestures until this one fails or doesn't start.
4612
4613#### Callbacks Common to All Gestures:
4614
4615- **onBegin(callback)**\
4616 Called when the handler starts receiving touches but hasn't yet recognized a gesture.
4617
4618- **onStart(callback)**\
4619 Triggered when the gesture is recognized and transitions to an active state.
4620
4621- **onEnd(callback)**\
4622 Invoked when a recognized gesture finishes, provided it was previously active.
4623
4624- **onFinalize(callback)**\
4625 Called upon finalizing gesture handling, whether successful or failed.
4626
4627- **onTouchesDown(callback)**\
4628 Triggered every time a finger touches the screen.
4629
4630- **onTouchesMove(callback)**\
4631 Activated whenever a finger moves on the screen.
4632
4633- **onTouchesUp(callback)**\
4634 Invoked when a finger is lifted from the screen.
4635
4636- **onTouchesCancelled(callback)**\
4637 Called when a touch stops being tracked, such as when a gesture ends.
4638
4639### Event Data Specific to `TapGesture`:
4640
4641- **x**\
4642 X coordinate of the pointer relative to the attached view.
4643
4644- **y**\
4645 Y coordinate of the pointer relative to the attached view.
4646
4647- **absoluteX**\
4648 Absolute X coordinate of the pointer relative to the window. Use this for transformed views.
4649
4650- **absoluteY**\
4651 Absolute Y coordinate of the pointer relative to the window. Use this for transformed views.
4652
4653### Event Attributes Common to All Gestures:
4654
4655- **state**\
4656 Current state of the handler, expressed as a constant from the `State` object.
4657
4658- **numberOfPointers**\
4659 Number of fingers currently on the screen.
4660
4661- **pointerType**\
4662 Type of pointer device in use, represented by the `PointerType` enum (`TOUCH`, `STYLUS`, `MOUSE`, `KEY`, `OTHER`).
4663
4664## Reanimated Swipeable
4665
4666### Overview
4667
4668This component serves as a replacement for the `Swipeable` component, utilizing `Reanimated`. It facilitates swipe interactions on rows or similar elements by rendering children within a panable container that supports horizontal swiping. Depending on the swipe direction (left or right), one of two "action" containers can be displayed using the `renderLeftActions` or `renderRightActions` props.
4669
4670### Usage
4671
4672To use this component, import it as follows:
4673
4674```typescript
4675import Swipeable from "react-native-gesture-handler/ReanimatedSwipeable"
4676```
4677
4678### Properties
4679
4680|Property|Description|
4681|-|-|
4682|`friction`|A number specifying the delay in visual interaction relative to gesture distance. E.g., `1` means no delay, `2` doubles it.|
4683|`leftThreshold`|Distance from the left edge for panel animation to open or close state. Defaults to half of the panel's width.|
4684|`rightThreshold`|Distance from the right edge for panel animation to open or close state. Defaults to half of the panel's width.|
4685|`dragOffsetFromLeftEdge`|Minimum drag distance from the left edge to consider a swipe (default: 10).|
4686|`dragOffsetFromRightEdge`|Minimum drag distance from the right edge to consider a swipe (default: 10).|
4687|`overshootLeft`|Boolean indicating if swiping beyond the left action panel's width is allowed. Defaults to `true` if `renderLeftActions` is provided.|
4688|`overshootRight`|Boolean indicating if swiping beyond the right action panel's width is allowed. Defaults to `true` if `renderRightActions` is provided.|
4689|`overshootFriction`|Number specifying delay in visual interaction at overshoot (default: 1). For a native feel, try `8` or above.|
4690
4691### Callbacks
4692
4693- **`onSwipeableOpen(direction)`**: Called when the swipeable opens.
4694- **`onSwipeableClose(direction)`**: Called when the swipeable closes.
4695- **`onSwipeableWillOpen(direction)`**: Called when opening animation starts.
4696- **`onSwipeableWillClose(direction)`**: Called when closing animation starts.
4697- **`onSwipeableOpenStartDrag(direction)`**: Called when a drag to open starts.
4698- **`onSwipeableCloseStartDrag(direction)`**: Called when a drag to close starts.
4699
4700### Render Functions
4701
4702#### `renderLeftActions`
4703
4704Returns a component rendered under the swipeable after swiping right. Arguments:
4705
4706- `progress`: Swiping progress relative to the width of the returned element.
4707- `translation`: Horizontal offset from closed position.
4708- `swipeableMethods`: Object with methods for interaction.
4709
4710Must return a `ReactNode`. Use `flexDirection` for RTL layouts.
4711
4712#### `renderRightActions`
4713
4714Returns a component rendered under the swipeable after swiping left. Arguments are similar to `renderLeftActions`.
4715
4716### Styles
4717
4718- **`containerStyle`**: Style object for the container (`Animated.View`).
4719- **`childrenContainerStyle`**: Style object for the children container (`Animated.View`).
4720
4721### Gesture Configuration
4722
4723#### `simultaneousWithExternalGesture`
4724
4725Allows recognition of another gesture simultaneously with the swipeable gesture. Useful for enabling other gestures like pan.
4726
4727Example:
4728
4729```typescript
4730const panGesture = Gesture.Pan();
4731
4732<GestureDetector gesture={panGesture}>
4733 <ReanimatedSwipeable simultaneousWithExternalGesture={panGesture} />
4734</GestureDetector>
4735```
4736
4737#### `enableTrackpadTwoFingerGesture` (iOS only)
4738
4739Enables two-finger gestures on supported devices, like iPads with trackpads.
4740
4741#### `mouseButton(value: MouseButton)` (Web & Android only)
4742
4743Specifies which mouse button should trigger the handler. Options include `LEFT`, `RIGHT`, `MIDDLE`, `BUTTON_4`, `BUTTON_5`, and `ALL`. Default is `MouseButton.LEFT`.
4744
4745#### `enableContextMenu(value: boolean)` (Web only)
4746
4747Determines if a context menu should be enabled after right-clicking on the underlying view. Default is `false`.
4748
4749### Methods
4750
4751Using a reference to `Swipeable`, you can trigger actions:
4752
4753- **`close`**: Closes the component.
4754- **`openLeft`**: Opens the component on the left side.
4755- **`openRight`**: Opens the component on the right side.
4756- **`reset`**: Resets swiping states without animation.
4757
4758### Example
4759
4760```typescript
4761import React from 'react';
4762import { Text, StyleSheet } from 'react-native';
4763import { GestureHandlerRootView } from 'react-native-gesture-handler';
4764import ReanimatedSwipeable from 'react-native-gesture-handler/ReanimatedSwipeable';
4765import Reanimated, {
4766 SharedValue,
4767 useAnimatedStyle,
4768} from 'react-native-reanimated';
4769
4770function RightAction(prog: SharedValue<number>, drag: SharedValue<number>) {
4771 const styleAnimation = useAnimatedStyle(() => {
4772 console.log('showRightProgress:', prog.value);
4773 console.log('appliedTranslation:', drag.value);
4774
4775 return {
4776 transform: [{ translateX: drag.value + 50 }],
4777 };
4778 });
4779
4780 return (
4781 <Reanimated.View style={styleAnimation}>
4782 <Text style={styles.rightAction}>Text</Text>
4783 </Reanimated.View>
4784 );
4785}
4786
4787export default function Example() {
4788 return (
4789 <GestureHandlerRootView>
4790 <ReanimatedSwipeable
4791 containerStyle={styles.swipeable}
4792 friction={2}
4793 enableTrackpadTwoFingerGesture
4794 rightThreshold={40}
4795 renderRightActions={RightAction}>
4796 <Text>Swipe me!</Text>
4797 </ReanimatedSwipeable>
4798 </GestureHandlerRootView>
4799 );
4800}
4801
4802const styles = StyleSheet.create({
4803 rightAction: { width: 50, height: 50, backgroundColor: 'purple' },
4804 swipeable: {
4805 height: 50,
4806 backgroundColor: 'papayawhip',
4807 alignItems: 'center',
4808 },
4809});
4810```
4811
4812## Swipeable
4813
4814**Caution:** This component facilitates the implementation of swipeable rows or similar interactions. It renders its children within a panable container, allowing for horizontal swiping left and right. Depending on whether the user swipes left or right, one of two "action" containers can be displayed, rendered by `renderLeftActions` or `renderRightActions` props.
4815
4816### Usage
4817
4818The `Swipeable` component is not exported by default from the `react-native-gesture-handler` package. To use it, import as follows:
4819
4820```typescript
4821import Swipeable from "react-native-gesture-handler/Swipeable"
4822```
4823
4824### Properties
4825
4826|Property|Description|
4827|-|-|
4828|`friction`|A number specifying how much the visual interaction will be delayed compared to the gesture distance. For example, a value of `1` means the swipeable panel follows the gesture exactly; `2` makes it two times "slower".|
4829|`leftThreshold`|Distance from the left edge at which the released panel animates to the open state (or vice versa). Default is half of the panel's width.|
4830|`rightThreshold`|Distance from the right edge for similar behavior as `leftThreshold`. Default is also half of the panel's width.|
4831|`dragOffsetFromLeftEdge`|Minimum distance that must be dragged from the left edge to consider it a swipe. Default value: `10`.|
4832|`dragOffsetFromRightEdge`|Similar to `dragOffsetFromLeftEdge`, but for the right edge. Default value: `10`.|
4833|`overshootLeft`|Boolean indicating if the panel can be pulled further than the left actions panel's width. Defaults to `true` if a left panel render method is present.|
4834|`overshootRight`|Similar to `overshootLeft`, but for the right side. Defaults to `true` if a right panel render method is present.|
4835|`overshootFriction`|Number specifying visual interaction delay at overshoot. Default value: `1`. For a native feel, try `8` or above.|
4836
4837**Deprecated Callbacks:**
4838
4839- `onSwipeableLeftOpen`: Deprecated; use `onSwipeableOpen(direction)`.
4840- `onSwipeableRightOpen`: Deprecated; use `onSwipeableOpen(direction)`.
4841
4842|Property|Description|
4843|-|-|
4844|`onSwipeableOpen`|Called when an action panel gets open (either right or left). Takes swipe direction as an argument.|
4845|`onSwipeableClose`|Called when the action panel is closed, with swipe direction as an argument.|
4846|`onSwipeableWillOpen`|Called when an action panel starts animating on open (either right or left), taking swipe direction as an argument.|
4847|`onSwipeableWillClose`|Called when an action panel starts animating on close, with swipe direction as an argument.|
4848
4849**Rendering Methods:**
4850
4851- `renderLeftActions`: Returns the left-side action panel revealed upon a right swipe.
4852
4853 - **Interpolation Values:**
4854 - `progressAnimatedValue`: `[0, 1]`
4855 - `dragAnimatedValue`: `[0, +]`
4856 - Use `flexDirection` for RTL flexbox layouts.
4857
4858- `renderRightActions`: Returns the right-side action panel revealed upon a left swipe.
4859 - **Interpolation Values:**
4860 - `progressAnimatedValue`: `[0, 1]`
4861 - `dragAnimatedValue`: `[0, -]`
4862 - Use `flexDirection` for RTL flexbox layouts.
4863
4864**Additional Styles:**
4865
4866- `containerStyle`: Style object for the container (Animated.View), e.g., to override `overflow: 'hidden'`.
4867- `childrenContainerStyle`: Style object for the children container (Animated.View), e.g., to apply `flex: 1`.
4868
4869**Platform-Specific Properties:**
4870
4871- `enableTrackpadTwoFingerGesture` (iOS only): Enables two-finger gestures on supported devices.
4872- `mouseButton(value: MouseButton)` (Web & Android only): Chooses which mouse button should trigger the handler. Options include:
4873 - `LEFT`
4874 - `RIGHT`
4875 - `MIDDLE`
4876 - `BUTTON_4`
4877 - `BUTTON_5`
4878 - `ALL` (default is `MouseButton.LEFT`)
4879- `enableContextMenu(value: boolean)` (Web only): Specifies if a context menu should be enabled after right-clicking. Default is `false`.
4880
4881### Methods
4882
4883Using a reference to `Swipeable`, you can trigger actions:
4884
4885|Method|Description|
4886|-|-|
4887|`close`|Closes the component with animation.|
4888|`openLeft`|Opens the component on the left side.|
4889|`openRight`|Opens the component on the right side.|
4890|`reset`|Resets swiping states without triggering any animation.|
4891
4892### Example
4893
4894```typescript
4895import React, { Component } from 'react';
4896import { Animated, StyleSheet, View, Text } from 'react-native';
4897import { RectButton } from 'react-native-gesture-handler';
4898import Swipeable from 'react-native-gesture-handler/Swipeable';
4899
4900class AppleStyleSwipeableRow extends Component {
4901 renderLeftActions = (progress, dragX) => {
4902 const trans = dragX.interpolate({
4903 inputRange: [0, 50, 100, 101],
4904 outputRange: [-20, 0, 0, 1],
4905 });
4906 return (
4907 <RectButton style={styles.leftAction} onPress={() => this.close()}>
4908 <Animated.Text
4909 style={[
4910 styles.actionText,
4911 {
4912 transform: [{ translateX: trans }],
4913 },
4914 ]}>
4915 Archive
4916 </Animated.Text>
4917 </RectButton>
4918 );
4919 };
4920
4921 render() {
4922 return (
4923 <Swipeable renderLeftActions={this.renderLeftActions}>
4924 <Text>"hello"</Text>
4925 </Swipeable>
4926 );
4927 }
4928}
4929
4930const styles = StyleSheet.create({
4931 leftAction: {
4932 // Define your styles here
4933 },
4934 actionText: {
4935 // Define your styles here
4936 },
4937});
4938```
4939
4940## Touchables
4941
4942**Warning:**\
4943Touchables will be deprecated in future versions of Gesture Handler. It is recommended to use `Pressable` instead.
4944
4945The Gesture Handler library offers an implementation of React Native's (RN) touchable components that are based on native buttons, avoiding reliance on the JavaScript responder system used by RN. This touchable implementation follows the same API and aims to be a direct replacement for the touchables available in React Native.
4946
4947React Native's touchables API includes:
4948
4949- Touchable Native Feedback
4950- Touchable Highlight
4951- Touchable Opacity
4952- Touchable Without Feedback
4953
4954All major properties of these touchables (except `pressRetentionOffset`) have been adopted, ensuring similar behavior to RN's touchables.
4955
4956The motivation for using RNGH touchables as a replacement is to more closely follow native behavior by utilizing the platform's native touch system instead of relying on the JS responder system. These touchables and their feedback behaviors are deeply integrated with the native gesture ecosystem, allowing easy connection with other native components (e.g., `ScrollView`) and Gesture Handlers in a predictable manner that aligns with native apps' behavior.
4957
4958The intention was to make switching to these touchables as straightforward as possible. To use RNGH's touchables, you only need to change the library from which you import the touchable components.
4959
4960**Info:**\
4961Gesture Handler's `TouchableOpacity` uses a native driver for animations by default. If this causes issues, you can set the `useNativeAnimations` prop to false.
4962
4963#### Example:
4964
4965Replace imports like so:
4966
4967```typescript
4968import {
4969 TouchableNativeFeedback,
4970 TouchableHighlight,
4971 TouchableOpacity,
4972 TouchableWithoutFeedback,
4973} from "react-native"
4974```
4975
4976with:
4977
4978```typescript
4979import {
4980 TouchableNativeFeedback,
4981 TouchableHighlight,
4982 TouchableOpacity,
4983 TouchableWithoutFeedback,
4984} from "react-native-gesture-handler"
4985```
4986
4987For a comparison of both touchable implementations, refer to our touchables example.
4988
4989## Handler State
4990
4991Gesture handlers are conceptualized as "state machines" according to the description provided in "About Gesture Handlers". This means they operate through a series of states, transitioning between them based on specific inputs or events.
4992
4993## How does it work?
4994
4995### Units
4996
4997All properties and event attributes in handler components representing onscreen dimensions are expressed in screen density-independent units called "points." These units align with those used in the React Native ecosystem, such as iOS's points and Android's dp (density-independent pixels). Points do not directly correspond to physical pixels.
4998
4999### iOS Implementation
5000
5001Gestures on iOS utilize UIGestureRecognizers. Some recognizers have been customized for enhanced customization and to adhere to the state flow of RNGH (React Native Gesture Handler). When a gesture configuration is assigned to `GestureDetector`, it creates all necessary recognizers and assigns them to the child view of the detector. Subsequently, most processing is managed by UIKit, with assistance from our implementation to ensure correct interactions between gestures.
5002
5003### Android Implementation
5004
5005Android lacks an easy method for handling gestures, necessitating custom implementations, including a system for managing gesture interactions. Here's how it functions:
5006
50071. **GestureHandlerRootView**: Wrapping a component in `GestureHandlerRootView` allows RNGH to intercept all touch events on that component and determine whether they should be handled by gesture handlers or passed to the underlying view.
5008
50091. **Touch Event Handling**:
5010
5011 - Gesture handlers are initialized when a gesture configuration is assigned to `GestureDetector`.
5012 - Each `GestureHandlerRootView` has a handler to decide if touch events should be consumed or passed through.
5013 - This handler cannot activate but can begin, end, or be cancelled.
5014
50151. **State Transitions**:
5016
5017 - In the `UNDETERMINED` state, no touch is in progress. Upon touch start, it transitions to the `BEGAN` state.
5018 - While in the `BEGAN` state, touch events are not consumed. If a handler activates (or gets cancelled), all incoming touch events are consumed, preventing them from reaching the underlying view.
5019
50201. **Gesture Recognition**:
5021
5022 - When a pointer touches the screen, the view tree is traversed to extract handlers attached to views beneath the finger, including those on `GestureHandlerRootView`.
5023 - Extracted handlers transition to the `BEGAN` state, indicating a potential gesture start.
5024 - Touch events are delivered to all extracted handlers until one recognizes and attempts to activate the gesture.
5025
50261. **Orchestrator Role**:
5027 - The orchestrator checks if the activating gesture should wait for other gestures to fail.
5028 - If it waits, it is placed on a waiting list; otherwise, it activates, cancelling non-simultaneous gestures.
5029 - When a gesture handler finishes (gesture recognized, fails, or cancels), the orchestrator reviews waiting handlers. Those that waited for the failed gesture attempt activation again, with the process repeating as necessary.
5030
5031This system ensures efficient and accurate gesture handling across both iOS and Android platforms.