this repo has no description
at main 193 kB view raw
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.