From 0e9675fde88f69a08c96402dbeb9b219d35d1cad Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Wed, 13 Apr 2022 18:07:13 +0200 Subject: [PATCH] Prepare for 2.4.0 release (#2006) - add version 2.4.0 to docs - update version in `package.json` - update `Podfile.lock`s in example apps - Small fix for `enabled` prop on `RNGHButton` on Fabric --- FabricExample/ios/Podfile.lock | 6 +- .../version-2.4.0/api/components/buttons.mdx | 170 +++++++++++++ .../api/components/drawer-layout.mdx | 147 ++++++++++++ .../version-2.4.0/api/components/swipeable.md | 190 +++++++++++++++ .../api/components/touchables.md | 52 ++++ .../base-continous-gesture-callbacks.md | 9 + .../gestures/base-continous-gesture-config.md | 5 + .../api/gestures/base-gesture-callbacks.md | 33 +++ .../api/gestures/base-gesture-config.md | 59 +++++ .../api/gestures/base-gesture-event-data.md | 9 + .../api/gestures/composed-gestures.md | 7 + .../api/gestures/fling-gesture.md | 86 +++++++ .../api/gestures/force-touch-gesture.md | 54 +++++ .../gestures/gesture-detector-functional1.md | 19 ++ .../api/gestures/gesture-detector.md | 27 +++ .../version-2.4.0/api/gestures/gesture.md | 55 +++++ .../api/gestures/long-press-gesture.md | 73 ++++++ .../api/gestures/manual-gesture.md | 25 ++ .../api/gestures/native-gesture.md | 40 +++ .../version-2.4.0/api/gestures/pan-gesture.md | 163 +++++++++++++ .../api/gestures/pinch-gesture.md | 77 ++++++ .../api/gestures/rotation-gesture.md | 74 ++++++ .../api/gestures/state-manager.md | 26 ++ .../version-2.4.0/api/gestures/tap-gesture.md | 100 ++++++++ .../api/gestures/touch-events.md | 49 ++++ .../version-2.4.0/api/test-api.md | 108 +++++++++ .../version-2.4.0/gesture-composition.md | 181 ++++++++++++++ .../gesture-handlers/api/common-gh.md | 93 +++++++ .../api/create-native-wrapper.md | 27 +++ .../gesture-handlers/api/fling-gh.md | 76 ++++++ .../gesture-handlers/api/force-gh.md | 67 ++++++ .../gesture-handlers/api/longpress-gh.md | 70 ++++++ .../gesture-handlers/api/nativeview-gh.md | 27 +++ .../gesture-handlers/api/pan-gh.md | 227 ++++++++++++++++++ .../gesture-handlers/api/pinch-gh.md | 89 +++++++ .../gesture-handlers/api/rotation-gh.md | 84 +++++++ .../gesture-handlers/api/tap-gh.md | 92 +++++++ .../gesture-handlers/basics/about-handlers.md | 129 ++++++++++ .../gesture-handlers/basics/interactions.md | 97 ++++++++ .../gesture-handlers/basics/state.md | 88 +++++++ .../guides/migrating-off-rnghenabledroot.md | 45 ++++ .../version-2.4.0/guides/testing.md | 28 +++ .../version-2.4.0/installation.md | 172 +++++++++++++ .../version-2.4.0/introduction.md | 115 +++++++++ .../manual-gestures/manual-gestures.md | 77 ++++++ .../version-2.4.0/manual-gestures/step1.md | 7 + .../version-2.4.0/manual-gestures/step2.md | 35 +++ .../version-2.4.0/manual-gestures/step3.md | 29 +++ .../version-2.4.0/manual-gestures/step4.md | 15 ++ .../version-2.4.0/manual-gestures/step5.md | 13 + .../version-2.4.0/manual-gestures/step6.md | 17 ++ .../version-2.4.0/manual-gestures/step7.md | 10 + .../version-2.4.0/quickstart/quickstart.md | 67 ++++++ .../version-2.4.0/quickstart/step1.md | 11 + .../version-2.4.0/quickstart/step2.md | 9 + .../version-2.4.0/quickstart/step3.md | 14 ++ .../version-2.4.0/quickstart/step4.md | 9 + .../version-2.4.0/quickstart/step5.md | 32 +++ .../version-2.4.0/troubleshooting.md | 35 +++ .../under-the-hood/how-does-it-work.md | 22 ++ .../under-the-hood/states-events.md | 94 ++++++++ .../version-2.4.0-sidebars.json | 210 ++++++++++++++++ docs/versions.json | 1 + example/ios/Podfile.lock | 6 +- ios/RNGestureHandlerButtonComponentView.mm | 2 +- package.json | 2 +- 66 files changed, 4079 insertions(+), 8 deletions(-) create mode 100644 docs/versioned_docs/version-2.4.0/api/components/buttons.mdx create mode 100644 docs/versioned_docs/version-2.4.0/api/components/drawer-layout.mdx create mode 100644 docs/versioned_docs/version-2.4.0/api/components/swipeable.md create mode 100644 docs/versioned_docs/version-2.4.0/api/components/touchables.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/base-continous-gesture-callbacks.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/base-continous-gesture-config.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/base-gesture-callbacks.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/base-gesture-config.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/base-gesture-event-data.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/composed-gestures.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/fling-gesture.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/force-touch-gesture.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/gesture-detector-functional1.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/gesture-detector.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/gesture.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/long-press-gesture.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/manual-gesture.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/native-gesture.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/pan-gesture.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/pinch-gesture.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/rotation-gesture.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/state-manager.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/tap-gesture.md create mode 100644 docs/versioned_docs/version-2.4.0/api/gestures/touch-events.md create mode 100644 docs/versioned_docs/version-2.4.0/api/test-api.md create mode 100644 docs/versioned_docs/version-2.4.0/gesture-composition.md create mode 100644 docs/versioned_docs/version-2.4.0/gesture-handlers/api/common-gh.md create mode 100644 docs/versioned_docs/version-2.4.0/gesture-handlers/api/create-native-wrapper.md create mode 100644 docs/versioned_docs/version-2.4.0/gesture-handlers/api/fling-gh.md create mode 100644 docs/versioned_docs/version-2.4.0/gesture-handlers/api/force-gh.md create mode 100644 docs/versioned_docs/version-2.4.0/gesture-handlers/api/longpress-gh.md create mode 100644 docs/versioned_docs/version-2.4.0/gesture-handlers/api/nativeview-gh.md create mode 100644 docs/versioned_docs/version-2.4.0/gesture-handlers/api/pan-gh.md create mode 100644 docs/versioned_docs/version-2.4.0/gesture-handlers/api/pinch-gh.md create mode 100644 docs/versioned_docs/version-2.4.0/gesture-handlers/api/rotation-gh.md create mode 100644 docs/versioned_docs/version-2.4.0/gesture-handlers/api/tap-gh.md create mode 100644 docs/versioned_docs/version-2.4.0/gesture-handlers/basics/about-handlers.md create mode 100644 docs/versioned_docs/version-2.4.0/gesture-handlers/basics/interactions.md create mode 100644 docs/versioned_docs/version-2.4.0/gesture-handlers/basics/state.md create mode 100644 docs/versioned_docs/version-2.4.0/guides/migrating-off-rnghenabledroot.md create mode 100644 docs/versioned_docs/version-2.4.0/guides/testing.md create mode 100644 docs/versioned_docs/version-2.4.0/installation.md create mode 100644 docs/versioned_docs/version-2.4.0/introduction.md create mode 100644 docs/versioned_docs/version-2.4.0/manual-gestures/manual-gestures.md create mode 100644 docs/versioned_docs/version-2.4.0/manual-gestures/step1.md create mode 100644 docs/versioned_docs/version-2.4.0/manual-gestures/step2.md create mode 100644 docs/versioned_docs/version-2.4.0/manual-gestures/step3.md create mode 100644 docs/versioned_docs/version-2.4.0/manual-gestures/step4.md create mode 100644 docs/versioned_docs/version-2.4.0/manual-gestures/step5.md create mode 100644 docs/versioned_docs/version-2.4.0/manual-gestures/step6.md create mode 100644 docs/versioned_docs/version-2.4.0/manual-gestures/step7.md create mode 100644 docs/versioned_docs/version-2.4.0/quickstart/quickstart.md create mode 100644 docs/versioned_docs/version-2.4.0/quickstart/step1.md create mode 100644 docs/versioned_docs/version-2.4.0/quickstart/step2.md create mode 100644 docs/versioned_docs/version-2.4.0/quickstart/step3.md create mode 100644 docs/versioned_docs/version-2.4.0/quickstart/step4.md create mode 100644 docs/versioned_docs/version-2.4.0/quickstart/step5.md create mode 100644 docs/versioned_docs/version-2.4.0/troubleshooting.md create mode 100644 docs/versioned_docs/version-2.4.0/under-the-hood/how-does-it-work.md create mode 100644 docs/versioned_docs/version-2.4.0/under-the-hood/states-events.md create mode 100644 docs/versioned_sidebars/version-2.4.0-sidebars.json diff --git a/FabricExample/ios/Podfile.lock b/FabricExample/ios/Podfile.lock index 4c0984c674..ec9a6f54b8 100644 --- a/FabricExample/ios/Podfile.lock +++ b/FabricExample/ios/Podfile.lock @@ -717,7 +717,7 @@ PODS: - React-jsi (= 0.68.0-rc.4) - React-logger (= 0.68.0-rc.4) - React-perflogger (= 0.68.0-rc.4) - - RNGestureHandler (2.3.2): + - RNGestureHandler (2.4.0): - RCT-Folly (= 2021.06.28.00-v2) - RCTRequired - RCTTypeSafety @@ -966,7 +966,7 @@ SPEC CHECKSUMS: React-rncore: 2862dc44212ee7785656c7f2f801abbeb6df8a4b React-runtimeexecutor: 6f69253af03039d3ab7c226421f0536da92b0d7a ReactCommon: 9044455ada87b8063b3dd8d9ef113c82b1d333a4 - RNGestureHandler: 7fc15a5a001ce68432434f3a351771b28104cdba + RNGestureHandler: a579421e0eb679a57717c8d44483a043b77949cb RNScreens: 9c1dfa815b0e70f24453f6acd1fb26090ddd38cb SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 Yoga: 13fdbd4e5a493556d2875b0be6f1ef62b6fd6c3e @@ -974,4 +974,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: bd25b1c4c8681669d4464e9327112993bb6e5dec -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 diff --git a/docs/versioned_docs/version-2.4.0/api/components/buttons.mdx b/docs/versioned_docs/version-2.4.0/api/components/buttons.mdx new file mode 100644 index 0000000000..6cfa2b4d86 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/components/buttons.mdx @@ -0,0 +1,170 @@ +--- +id: buttons +title: Buttons +sidebar_label: Buttons +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; +import GifGallery from '@site/components/GifGallery'; + + + + + +Gesture handler library provides native components that can act as buttons. These can be treated as a replacement to `TouchableHighlight` or `TouchableOpacity` from RN core. Gesture handler's buttons recognize touches in native which makes the recognition process deterministic, allows for rendering ripples on Android in highly performant way (`TouchableNativeFeedback` requires that touch event does a roundtrip to JS before we can update ripple effect, which makes ripples lag a bit on older phones), and provides native and platform default interaction for buttons that are placed in a scrollable container (in which case the interaction is slightly delayed to prevent button from highlighting when you fling). + +Currently Gesture handler library exposes three components that render native touchable elements under the hood: + +- `BaseButton` +- `RectButton` +- `BorderlessButton` + +On top of that all the buttons are wrapped with `NativeViewGestureHandler` and therefore allow for all the [common gesture handler properties](#common-gesturehandler-properties) and `NativeViewGestureHandler`'s [extra properties](#nativeviewgesturehandler-extra-properties) to be applied to them. + +**IMPORTANT**: In order to make buttons accessible, you have to wrap your children in a `View` with `accessible` and `accessibilityRole="button"` props. +Example: + +```javascript +// Not accessible: +const NotAccessibleButton = () => ( + + Foo + +); +// Accessible: +const AccessibleButton = () => ( + + + Bar + + +); +``` + +It is applicable for both iOS and Android platform. On iOS, you won't be able to even select the button, on Android you won't be able to click it in accessibility mode. + +## `BaseButton` + +Can be used as a base class if you'd like to implement some custom interaction for when the button is pressed. + +Below is a list of properties specific to `BaseButton` component: + +### `onActiveStateChange` + +function that gets triggered when button changes from inactive to active and vice versa. It passes active state as a boolean variable as a first parameter for that method. + +### `onPress` + +function that gets triggered when the button gets pressed (analogous to `onPress` in `TouchableHighlight` from RN core). + +### `rippleColor` (**Android only**) + +defines color of native [ripple](https://developer.android.com/reference/android/graphics/drawable/RippleDrawable) animation used since API level 21. + +### `exclusive` + +defines if more than one button could be pressed simultaneously. By default set `true`. + +## `RectButton` + +This type of button component should be used when you deal with rectangular elements or blocks of content that can be pressed, for example table rows or buttons with text and icons. This component provides a platform specific interaction, rendering a rectangular ripple on Android or highlighting the background on iOS and on older versions of Android. In addition to the props of [`BaseButton`](#basebutton-component), it accepts the following: + +Below is a list of properties specific to `RectButton` component: + +### `underlayColor` + +this is the background color that will be dimmed when button is in active state. + +### `activeOpacity` (**iOS only**) + +opacity applied to the underlay when button is in active state. + +## `BorderlessButton` + +This type of button component should be used with simple icon-only or text-only buttons. The interaction will be different depending on platform: on Android a borderless ripple will be rendered (it means that the ripple will animate into a circle that can span outside of the view bounds), whereas on iOS the button will be dimmed (similar to how `TouchableOpacity` works). In addition to the props of [`BaseButton`](#basebutton-component), it accepts the following: + +Below is a list of properties specific to `BorderlessButton` component: + +### `borderless` (**Android only**) + +set this to `false` if you want the ripple animation to render only within view bounds. + +### `activeOpacity` (**iOS only**) + +opacity applied to the button when it is in an active state. + +## Design patterns + +Components listed here were not designed to behave and look in the same way on both platforms but rather to be used for handling similar behaviour on iOS and Android taking into consideration their's design concepts. + +If you wish to get specific information about platforms design patterns, visit [official Apple docs](https://developer.apple.com/design/human-interface-guidelines/ios/controls) and [Material.io guideline](https://material.io/design/components/buttons.html#text-button), which widely describe how to implement coherent design. + +This library allows to use native components with native feedback in adequate situations. + +If you do not wish to implement custom design approach, `RectButton` and `BorderlessButton` seem to be absolutely enough and there's no need to use anything else. In all the remaining cases you can always rely on `BaseButton` which is a superclass for the other button classes and can be used as a generic `Touchable` replacement that can be customized to your needs. + +Below we list some of the common usecases for button components to be used along with the type of button that should be used according to the platform specific design guidelines. + +### Lists and action buttons + +If you have a list with clickable items or have an action button that need to display as a separate UI block (vs being inlined in a text) you should use `RectButton`. It changes opacity on click and additionally supports a ripple effect on Android. + + + + + + +To determine emphasis of button it's vital to use fill color or leave it transparent especially on Android. +For medium emphasis you may consider outlined buttons which are used for lower impact than fill buttons. + + + + + +### Icon or text only buttons + +Use `BorderlessButton` for simple icon-only or text-only buttons. The interaction will be different depending on platform: on Android a borderless ripple will be rendered, whereas on iOS the button will be dimmed. +It should be used if you wish to handle non-crucial actions and supportive behaviour. + + + + + + +### `PureNativeButton` + +Use a `PureNativeButton` for accessing the native Component used for build more complex buttons listed above. +It's normally is not recommended to use, but it might be useful if we want to wrap it using Animated or Reanimated. + +```javascript +import { + createNativeWrapper, + PureNativeButton, +} from 'react-native-gesture-handler'; +import Animated from 'react-native-reanimated'; +const { event, Value, createAnimatedComponent } = Animated; + +const AnimatedRawButton = createNativeWrapper( + createAnimatedComponent(PureNativeButton), + { + shouldCancelWhenOutside: false, + shouldActivateOnStart: false, + } +); + +export default class App extends React.Component { + constructor(props) { + super(props); + const state = new Value(); + this._onGestureEvent = event([ + { + nativeEvent: { state }, + }, + ]); + } + + render() { + return ; + } +} +``` diff --git a/docs/versioned_docs/version-2.4.0/api/components/drawer-layout.mdx b/docs/versioned_docs/version-2.4.0/api/components/drawer-layout.mdx new file mode 100644 index 0000000000..0f6fce24d6 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/components/drawer-layout.mdx @@ -0,0 +1,147 @@ +--- +id: drawer-layout +title: Drawer Layout +sidebar_label: DrawerLayout +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; +import GifGallery from '@site/components/GifGallery'; + +This is a cross-platform replacement for React Native's [DrawerLayoutAndroid](http://facebook.github.io/react-native/docs/drawerlayoutandroid.html) component. It provides a compatible API but allows for the component to be used on both Android and iOS. Please refer to [React Native docs](http://facebook.github.io/react-native/docs/drawerlayoutandroid.html) for the detailed usage for standard parameters. + +## Usage: + +`DrawerLayout` component isn't exported by default from the `react-native-gesture-handler` package. To use it, import it in the following way: + +```js +import DrawerLayout from 'react-native-gesture-handler/DrawerLayout'; +``` + +## Properties: + +On top of the standard list of parameters DrawerLayout has an additional set of attributes to customize its behavior. Please refer to the list below: + +### `drawerType` + +possible values are: `front`, `back` or `slide` (default is `front`). It specifies the way the drawer will be displayed. When set to `front` the drawer will slide in and out along with the gesture and will display on top of the content view. When `back` is used the drawer displays behind the content view and can be revealed with gesture of pulling the content view to the side. Finally `slide` option makes the drawer appear like it is attached to the side of the content view; when you pull both content view and drawer will follow the gesture. + +Type `slide`: + + + + + +Type `front`: + + + + + +Type `back`: + + + + + +### `edgeWidth` + +number, allows for defining how far from the edge of the content view the gesture should activate. + +### `hideStatusBar` + +boolean, when set to `true` Drawer component will use [StatusBar](http://facebook.github.io/react-native/docs/statusbar.html) API to hide the OS status bar whenever the drawer is pulled or when its in an "open" state. + +### `statusBarAnimation` + +possible values are: `slide`, `none` or `fade` (defaults to `slide`). Can be used when `hideStatusBar` is set to `true` and will select the animation used for hiding/showing the status bar. See [StatusBar](http://facebook.github.io/react-native/docs/statusbar.html#statusbaranimation) documentation for more details. + +### `overlayColor` + +color (default to `"black"`) of a semi-transparent overlay to be displayed on top of the content view when drawer gets open. A solid color should be used as the opacity is added by the Drawer itself and the opacity of the overlay is animated (from 0% to 70%). + +### `renderNavigationView` + +function. This attribute is present in the standard implementation already and is one of the required params. Gesture handler version of DrawerLayout make it possible for the function passed as `renderNavigationView` to take an Animated value as a parameter that indicates the progress of drawer opening/closing animation (progress value is 0 when closed and 1 when opened). This can be used by the drawer component to animated its children while the drawer is opening or closing. + +### `onDrawerClose` + +function. This function is called when the drawer is closed. + +### `onDrawerOpen` + +function. This function is called when the drawer is opened. + +### `onDrawerSlide` + +function. This function is called as a drawer sliding open from touch events. The progress of the drawer opening/closing is passed back as 0 when closed and 1 when opened. + +### `onDrawerStateChanged` + +function. This function is called when the status of the drawer changes. Possible values that can be passed back are: 'Idle', 'Dragging', and 'Settling'. + +### `enableTrackpadTwoFingerGesture` (iOS only) + +Enables two-finger gestures on supported devices, for example iPads with trackpads. If not enabled the gesture will require click + drag, with enableTrackpadTwoFingerGesture swiping with two fingers will also trigger the gesture. + +### `children` + +component or function. Children is a component which is rendered by default and is wrapped by drawer. However, it could be also a render function which takes an Animated value as a parameter that indicates the progress of drawer opening/closing animation (progress value is 0 when closed and 1 when opened) is the same way like `renderNavigationView` prop. + +## Methods + +### `openDrawer(options)` + +`openDrawer` can take an optional `options` parameter which is an object, enabling further customization of the open animation. + +`options` has two optional properties: + +`velocity`: number, the initial velocity of the object attached to the spring. Default 0 (object is at rest). +`speed`: number, controls speed of the animation. Default 12. + +### `closeDrawer(options)` + +`closeDrawer` can take an optional `options` parameter which is an object, enabling further customization of the close animation. + +`options` has two optional properties: + +`velocity`: number, the initial velocity of the object attached to the spring. Default 0 (object is at rest). +`speed`: number, controls speed of the animation. Default 12. + +## Example: + +See the [drawer example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/examples/Example/src/horizontalDrawer/index.tsx) from GestureHandler Example App or view it directly on your phone by visiting [our expo demo](https://snack.expo.io/@adamgrzybowski/react-native-gesture-handler-demo). + +```js +class Drawerable extends Component { + handleDrawerSlide = (status) => { + // outputs a value between 0 and 1 + console.log(status); + }; + + renderDrawer = () => { + return ( + + I am in the drawer! + + ); + }; + + render() { + return ( + + + + Hello, it's me + + + + ); + } +} +``` diff --git a/docs/versioned_docs/version-2.4.0/api/components/swipeable.md b/docs/versioned_docs/version-2.4.0/api/components/swipeable.md new file mode 100644 index 0000000000..18fb7dfe78 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/components/swipeable.md @@ -0,0 +1,190 @@ +--- +id: swipeable +title: Swipeable +sidebar_label: Swipeable +--- + +import useBaseUrl from '@docusaurus/useBaseUrl'; +import GifGallery from '@site/components/GifGallery' + + + + + +This component allows for implementing swipeable rows or similar interaction. It renders its children within a panable container allows for horizontal swiping left and right. While swiping one of two "action" containers can be shown depends on whether user swipes left or right (containers can be rendered by `renderLeftActions` or `renderRightActions` props). + +### Usage: + +Similarly to the `DrawerLayout`, `Swipeable` component isn't exported by default from the `react-native-gesture-handler` package. To use it, import it in the following way: + +```js +import Swipeable from 'react-native-gesture-handler/Swipeable'; +``` + +## Properties + +### `friction` + +a number that specifies how much the visual interaction will be delayed compared to the gesture distance. e.g. value of 1 will indicate that the swipeable panel should exactly follow the gesture, 2 means it is going to be two times "slower". + +### `leftThreshold` + +distance from the left edge at which released panel will animate to the open state (or the open panel will animate into the closed state). By default it's a half of the panel's width. + +### `rightThreshold` + +distance from the right edge at which released panel will animate to the open state (or the open panel will animate into the closed state). By default it's a half of the panel's width. + +### `overshootLeft` + +a boolean value indicating if the swipeable panel can be pulled further than the left actions panel's width. It is set to `true` by default as long as the left panel render method is present. + +### `overshootRight` + +a boolean value indicating if the swipeable panel can be pulled further than the right actions panel's width. It is set to `true` by default as long as the right panel render method is present. + +### `overshootFriction` + +a number that specifies how much the visual interaction will be delayed compared to the gesture distance at overshoot. Default value is 1, it mean no friction, for a native feel, try 8 or above. + +### `onSwipeableLeftOpen` + +:::caution +This callback is deprecated and will be removed in the next version. Please use `onSwipeableOpen(direction)` +::: + +method that is called when left action panel gets open. + +### `onSwipeableRightOpen` + +:::caution +This callback is deprecated and will be removed in the next version. Please use `onSwipeableOpen(direction)` +::: + +method that is called when right action panel gets open. + +### `onSwipeableOpen` + +method that is called when action panel gets open (either right or left). Takes swipe direction as +an argument. + +### `onSwipeableClose` + +method that is called when action panel is closed. Takes swipe direction as +an argument. + +### `onSwipeableLeftWillOpen` + +:::caution +This callback is deprecated and will be removed in the next version. Please use `onSwipeableWillOpen(direction)` +::: + +method that is called when left action panel starts animating on open. + +### `onSwipeableRightWillOpen` + +:::caution +This callback is deprecated and will be removed in the next version. Please use `onSwipeableWillOpen(direction)` +::: + +method that is called when right action panel starts animating on open. + +### `onSwipeableWillOpen` + +method that is called when action panel starts animating on open (either right or left). Takes swipe direction as +an argument. + +### `onSwipeableWillClose` + +method that is called when action panel starts animating on close. Takes swipe direction as +an argument. + +### `renderLeftActions` + +method that is expected to return an action panel that is going to be revealed from the left side when user swipes right. +This map describes the values to use as inputRange for extra interpolation: +AnimatedValue: [startValue, endValue] + +progressAnimatedValue: [0, 1] +dragAnimatedValue: [0, +] + +To support `rtl` flexbox layouts use `flexDirection` styling. + +### `renderRightActions` + +method that is expected to return an action panel that is going to be revealed from the right side when user swipes left. +This map describes the values to use as inputRange for extra interpolation: +AnimatedValue: [startValue, endValue] + +progressAnimatedValue: [0, 1] +dragAnimatedValue: [0, -] + +To support `rtl` flexbox layouts use `flexDirection` styling. + +### `containerStyle` + +style object for the container (Animated.View), for example to override `overflow: 'hidden'`. + +### `childrenContainerStyle` + +style object for the children container (Animated.View), for example to apply `flex: 1`. + +### `enableTrackpadTwoFingerGesture` (iOS only) + +Enables two-finger gestures on supported devices, for example iPads with trackpads. If not enabled the gesture will require click + drag, with enableTrackpadTwoFingerGesture swiping with two fingers will also trigger the gesture. + +## Methods + +Using reference to `Swipeable` it's possible to trigger some actions on it + +### `close` + +method that closes component. + +### `openLeft` + +method that opens component on left side. + +### `openRight` + +method that opens component on right side. + +### Example: + +See the [swipeable example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/showcase/swipeable/index.tsx) from GestureHandler Example App or view it directly on your phone by visiting [our expo demo](https://snack.expo.io/@adamgrzybowski/react-native-gesture-handler-demo). + +```js +import React, { Component } from 'react'; +import { Animated, StyleSheet, View } from 'react-native'; +import { RectButton } from 'react-native-gesture-handler'; +import Swipeable from 'react-native-gesture-handler/Swipeable'; + +class AppleStyleSwipeableRow extends Component { + renderLeftActions = (progress, dragX) => { + const trans = dragX.interpolate({ + inputRange: [0, 50, 100, 101], + outputRange: [-20, 0, 0, 1], + }); + return ( + + + Archive + + + ); + }; + render() { + return ( + + "hello" + + ); + } +} +``` diff --git a/docs/versioned_docs/version-2.4.0/api/components/touchables.md b/docs/versioned_docs/version-2.4.0/api/components/touchables.md new file mode 100644 index 0000000000..4b45292f72 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/components/touchables.md @@ -0,0 +1,52 @@ +--- +id: touchables +title: Touchables +sidebar_label: Touchables +--- + +Gesture Handler library provides an implementation of RN's touchable components that are based on [native buttons](buttons.mdx) and does not rely on JS responder system utilized by RN. Our touchable implementation follows the same API and aims to be a drop-in replacement for touchables available in React Native. + +React Native's touchables API can be found here: + +- [Touchable Native Feedback](https://facebook.github.io/react-native/docs/touchablenativefeedback) +- [Touchable Highlight](https://facebook.github.io/react-native/docs/touchablehighlight) +- [Touchable Opacity](https://facebook.github.io/react-native/docs/touchableopacity) +- [Touchable Without Feedback](https://facebook.github.io/react-native/docs/touchablewithoutfeedback) + +All major touchable properties (except from `pressRetentionOffset`) have been adopted and should behave in a similar way as with RN's touchables. + +The motivation for using RNGH touchables as a replacement for these imported from React Native is to follow built-in native behavior more closely by utilizing platform native touch system instead of relying on the JS responder system. +These touchables and their feedback behavior are deeply integrated with native +gesture ecosystem and could be connected with other native components (e.g. `ScrollView`) and Gesture Handlers easily and in a more predictable way, which +follows native apps' behavior. + +Our intention was to make switch for these touchables as simple as possible. In order to use RNGH's touchables the only thing you need to do is to change library from which you import touchable components. +need only to change imports of touchables. + +:::info +Gesture Handler's TouchableOpacity uses native driver for animations by default. If this causes problems for you, you can set `useNativeAnimations` prop to false. +::: + +### Example: + +```javascript +import { + TouchableNativeFeedback, + TouchableHighlight, + TouchableOpacity, + TouchableWithoutFeedback, +} from 'react-native'; +``` + +has to be replaced with: + +```javascript +import { + TouchableNativeFeedback, + TouchableHighlight, + TouchableOpacity, + TouchableWithoutFeedback, +} from 'react-native-gesture-handler'; +``` + +For a comparison of both touchable implementations see our [touchables example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/release_tests/touchables/index.tsx) diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/base-continous-gesture-callbacks.md b/docs/versioned_docs/version-2.4.0/api/gestures/base-continous-gesture-callbacks.md new file mode 100644 index 0000000000..5504b2db8d --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/base-continous-gesture-callbacks.md @@ -0,0 +1,9 @@ +### Callbacks common to all continous gestures: + +### `onUpdate(callback)` + +Set the callback that is being called every time the gesture receives an update while it's active. + +### `onChange(callback)` + +Set the callback that is being called every time the gesture receives an update while it's active. This callback will receive information about change in value in relation to the last received event. diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/base-continous-gesture-config.md b/docs/versioned_docs/version-2.4.0/api/gestures/base-continous-gesture-config.md new file mode 100644 index 0000000000..a19473784e --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/base-continous-gesture-config.md @@ -0,0 +1,5 @@ +### Properties common to all continous gestures: + +### `manualActivation(value: boolead)` + +When `true` the handler will not activate by itself even if its activation criteria are met. Instead you can manipulate its state using [state manager](./state-manager.md). diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/base-gesture-callbacks.md b/docs/versioned_docs/version-2.4.0/api/gestures/base-gesture-callbacks.md new file mode 100644 index 0000000000..dff985b307 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/base-gesture-callbacks.md @@ -0,0 +1,33 @@ +### Callbacks common to all gestures: + +### `onBegin(callback)` + +Set the callback that is being called when given gesture handler starts receiving touches. At the moment of this callback the handler is not yet in an active state and we don't know yet if it will recognize the gesture at all. + +### `onStart(callback)` + +Set the callback that is being called when the gesture is recognized by the handler and it transitions to the active state. + +### `onEnd(callback)` + +Set the callback that is being called when the gesture that was recognized by the handler finishes. It will be called only if the handler was previously in the active state. + +### `onFinalize(callback)` + +Set the callback that is being called when the handler finalizes handling gesture - the gesture was recognized and has finished or it failed to recognize. + +### `onTouchesDown(callback)` + +Set the `onTouchesDown` callback which is called every time a finger is placed on the screen. + +### `onTouchesMove(callback)` + +Set the `onTouchesMove` callback which is called every time a finger is moved on the screen. + +### `onTouchesUp(callback)` + +Set the `onTouchesUp` callback which is called every time a finger is lifted from the screen. + +### `onTouchesCancelled(callback)` + +Set the `onTouchesCancelled` callback which is called every time a finger stops being tracked, for example when the gesture finishes. diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/base-gesture-config.md b/docs/versioned_docs/version-2.4.0/api/gestures/base-gesture-config.md new file mode 100644 index 0000000000..0a41dd6ea6 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/base-gesture-config.md @@ -0,0 +1,59 @@ +### Properties common to all gestures: + +### `enabled(value: boolean)` + +Indicates whether the given handler should be analyzing stream of touch events or not. +When set to `false` we can be sure that the handler's state will **never** become [`ACTIVE`](../../under-the-hood/states-events.md#active). +If the value gets updated while the handler already started recognizing a gesture, then the handler's state it will immediately change to [`FAILED`](../../under-the-hood/states-events.md#failed) or [`CANCELLED`](../../under-the-hood/states-events.md#cancelled) (depending on its current state). +Default value is `true`. + +### `shouldCancelWhenOutside(value: boolean)` + +When `true` the handler will [cancel](../../under-the-hood/states-events.md#cancelled) or [fail](../../under-the-hood/states-events.md#failed) recognition (depending on its current state) whenever the finger leaves the area of the connected view. +Default value of this property is different depending on the handler type. +Most handlers' `shouldCancelWhenOutside` property defaults to `false` except for the [`LongPressGesture`](./long-press-gesture.md) and [`TapGesture`](./tap-gesture.md) which default to `true`. + +### `hitSlop(settings)` + +This parameter enables control over what part of the connected view area can be used to [begin](../../under-the-hood/states-events.md#began) recognizing the gesture. +When a negative number is provided the bounds of the view will reduce the area by the given number of points in each of the sides evenly. + +Instead you can pass an object to specify how each boundary side should be reduced by providing different number of points for `left`, `right`, `top` or `bottom` sides. +You can alternatively provide `horizontal` or `vertical` instead of specifying directly `left`, `right` or `top` and `bottom`. +Finally, the object can also take `width` and `height` attributes. +When `width` is set it is only allow to specify one of the sides `right` or `left`. +Similarly when `height` is provided only `top` or `bottom` can be set. +Specifying `width` or `height` is useful if we only want the gesture to activate on the edge of the view. In which case for example we can set `left: 0` and `width: 20` which would make it possible for the gesture to be recognize when started no more than 20 points from the left edge. + +**IMPORTANT:** Note that this parameter is primarily designed to reduce the area where gesture can activate. Hence it is only supported for all the values (except `width` and `height`) to be non positive (0 or lower). Although on Android it is supported for the values to also be positive and therefore allow to expand beyond view bounds but not further than the parent view bounds. To achieve this effect on both platforms you can use React Native's View [hitSlop](https://facebook.github.io/react-native/docs/view.html#props) property. + +### `withRef(ref)` + +Sets a ref to the gesture object, allowing for interoperability with the old +API. + +### `withTestId(testID)` + +Sets a `testID` property for gesture object, allowing for querying for it in tests. + +### `cancelsToucesInView(value)` (**iOS only**) +Accepts a boolean value. +When `true`, the gesture will cancel touches for native UI components (`UIButton`, `UISwitch`, etc) it's attached to when it becomes [`ACTIVE`](../../under-the-hood/states-events.md#active). +Default value is `true`. + +### `runOnJS(value: boolean)` + +When `react-native-reanimated` is installed, the callbacks passed to the gestures are automatically workletized and run on the UI thread when called. This option allows for changing this behavior: when `true`, all the callbacks will be run on the JS thread instead of the UI thread, regardless of whether they are worklets or not. +Defaults to `false`. + +### `simultaneousWithExternalGesture(otherGesture1, otherGesture2, ...)` + +Adds a gesture that should be recognized simultaneously with this one. + +**IMPORTANT:** Note that this method only marks the relation between gestures, without [composing them](../../gesture-composition). [`GestureDetector`](gesture-detector) will not recognize the `otherGestures` and it needs to be added to another detector in order to be recognized. + +### `requireExternalGestureToFail(otherGesture1, otherGesture2, ...)` + +Adds a relation requiring another gesture to fail, before this one can activate. + +**IMPORTANT:** Note that this method only marks the relation between gestures, without [composing them](../../gesture-composition).[`GestureDetector`](gesture-detector) will not recognize the `otherGestures` and it needs to be added to another detector in order to be recognized. diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/base-gesture-event-data.md b/docs/versioned_docs/version-2.4.0/api/gestures/base-gesture-event-data.md new file mode 100644 index 0000000000..4d9056b1e5 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/base-gesture-event-data.md @@ -0,0 +1,9 @@ +### Event attributes common to all gestures: + +### `state` + +Current [state](.../../under-the-hood/states-events.md) of the handler. Expressed as one of the constants exported under `State` object by the library. + +### `numberOfPointers` + +Represents the number of pointers (fingers) currently placed on the screen. diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/composed-gestures.md b/docs/versioned_docs/version-2.4.0/api/gestures/composed-gestures.md new file mode 100644 index 0000000000..84e2e451bd --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/composed-gestures.md @@ -0,0 +1,7 @@ +--- +id: composed-gestures +title: Composed gestures +sidebar_label: Composed gestures +--- + +Composed gestures (`Race`, `Simultaneous`, `Exclusive`) provide a simple way of building relations between gestures. diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/fling-gesture.md b/docs/versioned_docs/version-2.4.0/api/gestures/fling-gesture.md new file mode 100644 index 0000000000..09c2846276 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/fling-gesture.md @@ -0,0 +1,86 @@ +--- +id: fling-gesture +title: Fling gesture +sidebar_label: Fling gesture +--- + +import BaseEventData from './base-gesture-event-data.md'; +import BaseEventConfig from './base-gesture-config.md'; +import BaseEventCallbacks from './base-gesture-callbacks.md'; + +A discrete gesture that activates when the movement is sufficiently long and fast. +Gesture gets [ACTIVE](../../under-the-hood/states-events.md#active) when movement is sufficiently long and it does not take too much time. +When gesture gets activated it will turn into [END](../../under-the-hood/states-events.md#end) state when finger is released. +The gesture will fail to recognize if the finger is lifted before being activated. + +## Config + +### Properties specific to `FlingGesture`: + +### `direction(value: Directions)` + +Expressed allowed direction of movement. Expected values are exported as constants in the `Directions` object. It's possible to pass one or many directions in one parameter: + +```js +fling.direction(Directions.RIGHT | Directions.LEFT); +``` + +or + +```js +fling.direction(Directions.DOWN); +``` + +### `numberOfPointers(value: number)` + +Determine exact number of points required to handle the fling gesture. + + + +## Callbacks + + + +## Event data + +### Event attributes specific to `FlingGesture`: + +### `x` + +X coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the [`GestureDetector`](./gesture-detector.md). Expressed in point units. + +### `y` + +Y coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the [`GestureDetector`](./gesture-detector.md). Expressed in point units. + +### `absoluteX` + +X coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. The value is expressed in point units. It is recommended to use it instead of [`x`](#x) in cases when the original view can be transformed as an effect of the gesture. + +### `absoluteY` + +Y coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. The value is expressed in point units. It is recommended to use it instead of [`y`](#y) in cases when the original view can be transformed as an effect of the gesture. + + + +## Example + +```jsx +const position = useSharedValue(0); + +const flingGesture = Gesture.Fling() + .direction(Directions.RIGHT) + .onStart((e) => { + position.value = withTiming(position.value + 10, { duration: 100 }); + }); + +const animatedStyle = useAnimatedStyle(() => ({ + transform: [{ translateX: position.value }], +})); + +return ( + + + +); +``` diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/force-touch-gesture.md b/docs/versioned_docs/version-2.4.0/api/gestures/force-touch-gesture.md new file mode 100644 index 0000000000..8280f944b1 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/force-touch-gesture.md @@ -0,0 +1,54 @@ +--- +id: force-touch-gesture +title: Force touch gesture (iOS only) +sidebar_label: Force touch gesture +--- + +import BaseEventData from './base-gesture-event-data.md'; +import BaseEventConfig from './base-gesture-config.md'; +import BaseContinousEventConfig from './base-continous-gesture-config.md'; +import BaseEventCallbacks from './base-gesture-callbacks.md'; +import BaseContinousEventCallbacks from './base-continous-gesture-callbacks.md'; + +A continuous gesture that recognizes force of a touch. It allows for tracking pressure of touch on some iOS devices. +The gesture [activates](../../under-the-hood/states-events.md#active) when pressure of touch if greater or equal than `minForce`. It fails if pressure is greater than `maxForce` +Gesture callback can be used for continuous tracking of the touch pressure. It provides information for one finger (the first one). + +At the beginning of the gesture, the pressure factor is 0.0. As the pressure increases, the pressure factor increases proportionally. The maximum pressure is 1.0. + +There's no implementation provided on Android and it simply renders children without any wrappers. +Since this behaviour is only provided on some iOS devices, this gesture should not be used for defining any crucial behaviors. Use it only as an additional improvement and make all features to be accessed without this gesture as well. + +## Config + +### Properties specific to `ForceTouchGesture`: + +### `minForce(value: number)` + +A minimal pressure that is required before gesture can [activate](../../under-the-hood/states-events.md#active). Should be a value from range `[0.0, 1.0]`. Default is `0.2`. + +### `maxForce(value: number)` + +A maximal pressure that could be applied for gesture. If the pressure is greater, gesture [fails](../../under-the-hood/states-events.md#failed). Should be a value from range `[0.0, 1.0]`. + +### `feedbackOnActivation(value: boolean)` + +Value defining if haptic feedback has to be performed on activation. + + + + +## Callbacks + + + + +## Event data + +### Event attributes specific to `ForceTouchGesture`: + +### `force` + +The pressure of a touch. + + diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/gesture-detector-functional1.md b/docs/versioned_docs/version-2.4.0/api/gestures/gesture-detector-functional1.md new file mode 100644 index 0000000000..2397af9dfa --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/gesture-detector-functional1.md @@ -0,0 +1,19 @@ +```jsx +export default function Example() { + const tap = Gesture.Tap().onStart(() => { + console.log('tap'); + }); + + return ( + + + + + + ); +} + +function FunctionalComponent(props) { + return {props.children}; +} +``` diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/gesture-detector.md b/docs/versioned_docs/version-2.4.0/api/gestures/gesture-detector.md new file mode 100644 index 0000000000..ef8af9b62c --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/gesture-detector.md @@ -0,0 +1,27 @@ +--- +id: gesture-detector +title: GestureDetector +sidebar_label: Gesture detector +--- + +import FunctionalComponents from './gesture-detector-functional1.md'; + +`GestureDetector` is the main component of the RNGH2. It is responsible for creating and updating native gesture handlers based on the config of provided gesture. The most significant difference between it and old gesture handlers is that the `GestureDetector` can recognize more than one gesture at the time thanks to gesture composition. Keep in mind that `GestureDetector` is not compatible with the [Animated API](https://reactnative.dev/docs/animated), nor with [Reanimated 1](https://docs.swmansion.com/react-native-reanimated/docs/1.x.x/). + +:::caution +Gesture Detector will use first native view in its subtree to recognize gestures, however if this view is used only to group its children it may get automatically [collapsed](https://reactnative.dev/docs/view#collapsable-android). Consider this example: + +If we were to remove the collapsable prop from the View, the gesture would stop working because it would be attached to a view that is not present in the view hierarchy. Gesture Detector adds this prop automatically to its direct child but it's impossible to do automatically for more complex view trees. +::: + +## Properties + +### `gesture` + +A gesture object containing the configuration and callbacks. Can be any of the base gestures (`Tap`, `Pan`, `LongPress`, `Fling`, `Pinch`, `Rotation`, `ForceTouch`) or any [`ComposedGesture`](./composed-gestures.md) (`Race`, `Simultaneous`, `Exclusive`). + +:::info +GestureDetector will decide whether to use Reanimated to process provided gestures based on callbacks they have. If any of the callbacks is a worklet, tools provided by the Reanimated will be utilized bringing ability to handle gestures synchrously. + +Starting with Reanimated-2.3.0-beta.4 Gesture Handler will provide a [StateManager](./state-manager.md) in the [touch events](./touch-events.md) that allows for managing the state of the gesture. +::: diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/gesture.md b/docs/versioned_docs/version-2.4.0/api/gestures/gesture.md new file mode 100644 index 0000000000..a84a48003a --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/gesture.md @@ -0,0 +1,55 @@ +--- +id: gesture +title: Gesture +sidebar_label: Gesture +--- + +`Gesture` is the object that allows you to create and compose gestures. + +### Gesture.Tap() + +Creates a new instance of [`TapGesture`](./tap-gesture.md) with its default config and no callbacks. + +### Gesture.Pan() + +Creates a new instance of [`PanGesture`](./pan-gesture.md) with its default config and no callbacks. + +### Gesture.LongPress() + +Creates a new instance of [`LongPressGesture`](./long-press-gesture.md) with its default config and no callbacks. + +### Gesture.Fling() + +Creates a new instance of [`FlingGesture`](./fling-gesture.md) with its default config and no callbacks. + +### Gesture.Pinch() + +Creates a new instance of [`PinchGesture`](./pinch-gesture.md) with its default config and no callbacks. + +### Gesture.Rotation() + +Creates a new instance of [`RotationGesture`](./rotation-gesture.md) with its default config and no callbacks. + +### Gesture.ForceTouch() + +Creates a new instance of [`ForceTouchGesture`](./force-touch-gesture.md) with its default config and no callbacks. + +### Gesture.Manual() + +Creates a new instance of [`ManualGesture`](./manual-gesture.md) with its default config and no callbacks. + +### Gesture.Native() + +Creates a new instance of [`NativeGesture`](./native-gesture.md) with its default config and no callbacks. + +### Gesture.Race(gesture1, gesture2, gesture3, ...): ComposedGesture + +Creates a gesture composed of those provided as arguments. Only one of those can become active and there are no restrictions to the activation of the gesture. The first one to activate will cancel all the others. + +### Gesture.Simultaneous(gesture1, gesture2, gesture3, ...): ComposedGesture + +Creates a gesture composed of those provided as arguments. All of them can become active without cancelling the others. + +### Gesture.Exclusive(gesture1, gesture2, gesture3, ...): ComposedGesture + +Creates a gesture composed of those provided as arguments. Only one of them can become active, but the first one has a higher priority than the second one, the second one has a higher priority than the third one, and so on. When all gestures are in the `BEGAN` state and the activation criteria for the second one is met, instead of activating it will wait until the first one fails (and only then it will activate) or until the first one activates (and then the second one will get cancelled). It is useful when you want to compose gestures with similar activation criteria (e.g. single and double tap at the same component, without Exclusive the single tap would activate every time user taps thus cancelling the double tap). diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/long-press-gesture.md b/docs/versioned_docs/version-2.4.0/api/gestures/long-press-gesture.md new file mode 100644 index 0000000000..9f174d58e7 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/long-press-gesture.md @@ -0,0 +1,73 @@ +--- +id: long-press-gesture +title: Long press gesture +sidebar_label: Long press gesture +--- + +import BaseEventData from './base-gesture-event-data.md'; +import BaseEventConfig from './base-gesture-config.md'; +import BaseEventCallbacks from './base-gesture-callbacks.md'; + +A discrete gesture that activates when the corresponding view is pressed for a sufficiently long time. +This gesture's state will turn into [END](../../under-the-hood/states-events.md#end) immediately after the finger is released. +The gesture will fail to recognize a touch event if the finger is lifted before the [minimum required time](#mindurationms) or if the finger is moved further than the [allowable distance](#maxdist). + +## Config + +### Properties specific to `LongPressGesture`: + +### `minDuration(value: number)` + +Minimum time, expressed in milliseconds, that a finger must remain pressed on the corresponding view. The default value is 500. + +### `maxDistance(value: number)` + +Maximum distance, expressed in points, that defines how far the finger is allowed to travel during a long press gesture. If the finger travels further than the defined distance and the gesture hasn't yet [activated](../../under-the-hood/states-events.md#active), it will fail to recognize the gesture. The default value is 10. + + + +## Callbacks + + + +## Event data + +### Event attributes specific to `LongPressGesture`: + +### `x` + +X coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the [`GestureDetector`](./gesture-detector.md). + +### `y` + +Y coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the [`GestureDetector`](./gesture-detector.md). + +### `absoluteX` + +X coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. It is recommended to use `absoluteX` instead of [`x`](#x) in cases when the view attached to the [`GestureDetector`](./gesture-detector.md) can be transformed as an effect of the gesture. + +### `absoluteY` + +Y coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. It is recommended to use `absoluteY` instead of [`y`](#y) in cases when the view attached to the [`GestureDetector`](./gesture-detector.md) can be transformed as an effect of the gesture. + +### `duration` + +Duration of the long press (time since the start of the gesture), expressed in milliseconds. + + + +## Example + +```jsx +const longPressGesture = Gesture.LongPress().onEnd((e, success) => { + if (success) { + Alert.alert(`Long pressed for ${e.duration} ms!`); + } +}); + +return ( + + + +); +``` diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/manual-gesture.md b/docs/versioned_docs/version-2.4.0/api/gestures/manual-gesture.md new file mode 100644 index 0000000000..a92c6986ef --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/manual-gesture.md @@ -0,0 +1,25 @@ +--- +id: manual-gesture +title: Manual gesture +sidebar_label: Manual gesture +--- + +import BaseEventData from './base-gesture-event-data.md'; +import BaseEventConfig from './base-gesture-config.md'; +import BaseEventCallbacks from './base-gesture-callbacks.md'; +import BaseContinousEventCallbacks from './base-continous-gesture-callbacks.md'; + +A plain gesture that has no specific activation criteria nor event data set. Its state has to be controlled manually using a [state manager](./state-manager.md). It will not fail when all the pointers are lifted from the screen. + +## Config + + + +## Callbacks + + + + +## Event data + + diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/native-gesture.md b/docs/versioned_docs/version-2.4.0/api/gestures/native-gesture.md new file mode 100644 index 0000000000..6fa7249eed --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/native-gesture.md @@ -0,0 +1,40 @@ +--- +id: native-gesture +title: Native gesture +sidebar_label: Native gesture +--- + +import BaseEventData from './base-gesture-event-data.md'; +import BaseEventConfig from './base-gesture-config.md'; +import BaseEventCallbacks from './base-gesture-callbacks.md'; +import BaseContinousEventCallbacks from './base-continous-gesture-callbacks.md'; + +A gesture that allows other touch handling components to participate in RNGH's gesture system. When used, the other component should be the direct child of a `GestureDetector`. + +## Config + +### Properties specific to `NativeGesture`: + +### `shouldActivateOnStart(value: boolean)` (**Android only**) + +When `true`, underlying handler will activate unconditionally when in `BEGAN` or `UNDETERMINED` state. + +### `disallowInterruption(value: boolean)` + +When `true`, cancels all other gesture handlers when this `NativeViewGestureHandler` receives an `ACTIVE` state event. + + + +## Callbacks + + + +## Event data + +### Event attributes specific to `NativeGesture`: + +### `pointerInside` + +True if gesture was performed inside of containing view, false otherwise. + + diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/pan-gesture.md b/docs/versioned_docs/version-2.4.0/api/gestures/pan-gesture.md new file mode 100644 index 0000000000..c8be974e7f --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/pan-gesture.md @@ -0,0 +1,163 @@ +--- +id: pan-gesture +title: Pan gesture +sidebar_label: Pan gesture +--- + +import BaseEventData from './base-gesture-event-data.md'; +import BaseEventConfig from './base-gesture-config.md'; +import BaseContinousEventConfig from './base-continous-gesture-config.md'; +import BaseEventCallbacks from './base-gesture-callbacks.md'; +import BaseContinousEventCallbacks from './base-continous-gesture-callbacks.md'; + +A continuous gesture that can recognize a panning (dragging) gesture and track its movement. + +The gesture [activates](../../under-the-hood/states-events.md#active) when a finger is placed on the screen and moved some initial distance. + +Configurations such as a minimum initial distance, specific vertical or horizontal pan detection and [number of fingers](#minPointers) required for activation (allowing for multifinger swipes) may be specified. + +Gesture callback can be used for continuous tracking of the pan gesture. It provides information about the gesture such as its XY translation from the starting point as well as its instantaneous velocity. + +## Multi touch pan handling + +If your app relies on multi touch pan handling this section provides some information how the default behavior differs between the platform and how (if necessary) it can be unified. + +The difference in multi touch pan handling lies in the way how translation properties during the event are being calculated. +On iOS the default behavior when more than one finger is placed on the screen is to treat this situation as if only one pointer was placed in the center of mass (average position of all the pointers). +This applies also to many platform native components that handle touch even if not primarily interested in multi touch interactions like for example UIScrollView component. + +The default behavior for native components like scroll view, pager views or drawers is different and hence gesture defaults to that when it comes to pan handling. +The difference is that instead of treating the center of mass of all the fingers placed as a leading pointer it takes the latest placed finger as such. +This behavior can be changed on Android using [`avgTouches`](#avgtouches-android-only) flag. + +Note that on both Android and iOS when the additional finger is placed on the screen that translation prop is not affected even though the position of the pointer being tracked might have changed. +Therefore it is safe to rely on translation most of the time as it only reflects the movement that happens regardless of how many fingers are placed on the screen and if that number changes over time. +If you wish to track the "center of mass" virtual pointer and account for its changes when the number of finger changes you can use relative or absolute position provided in the event ([`x`](#x) and [`y`](#y) or [`absoluteX`](#absolutex) and [`absoluteY`](#absolutey)). + +## Config + +### Properties specific to `PanGesture`: + +### `minDistance(value: number)` + +Minimum distance the finger (or multiple finger) need to travel before the gesture [activates](../../under-the-hood/states-events.md#active). Expressed in points. + +### `minPointers(value: number)` + +A number of fingers that is required to be placed before gesture can [activate](../../under-the-hood/states-events.md#active). Should be a higher or equal to 0 integer. + +### `maxPointers(value: number)` + +When the given number of fingers is placed on the screen and gesture hasn't yet [activated](../../under-the-hood/states-events.md#active) it will fail recognizing the gesture. Should be a higher or equal to 0 integer. + +### `activeOffsetX(value: number | number[])` + +Range along X axis (in points) where fingers travels without activation of gesture. Moving outside of this range implies activation of gesture. Range can be given as an array or a single number. +If range is set as an array, first value must be lower or equal to 0, a the second one higher or equal to 0. +If only one number `p` is given a range of `(-inf, p)` will be used if `p` is higher or equal to 0 and `(-p, inf)` otherwise. + +### `activeOffsetY(value: number | number[])` + +Range along Y axis (in points) where fingers travels without activation of gesture. Moving outside of this range implies activation of gesture. Range can be given as an array or a single number. +If range is set as an array, first value must be lower or equal to 0, a the second one higher or equal to 0. +If only one number `p` is given a range of `(-inf, p)` will be used if `p` is higher or equal to 0 and `(-p, inf)` otherwise. + +### `failOffsetY(value: number | number[])` + +When the finger moves outside this range (in points) along Y axis and gesture hasn't yet activated it will fail recognizing the gesture. Range can be given as an array or a single number. +If range is set as an array, first value must be lower or equal to 0, a the second one higher or equal to 0. +If only one number `p` is given a range of `(-inf, p)` will be used if `p` is higher or equal to 0 and `(-p, inf)` otherwise. + +### `failOffsetX(value: number | number[])` + +When the finger moves outside this range (in points) along X axis and gesture hasn't yet activated it will fail recognizing the gesture. Range can be given as an array or a single number. +If range is set as an array, first value must be lower or equal to 0, a the second one higher or equal to 0. +If only one number `p` is given a range of `(-inf, p)` will be used if `p` is higher or equal to 0 and `(-p, inf)` otherwise. + +### `averageTouches(value: boolean)` (Android only) + +### `enableTrackpadTwoFingerGesture(value: boolean)` (iOS only) + +Enables two-finger gestures on supported devices, for example iPads with trackpads. If not enabled the gesture will require click + drag, with enableTrackpadTwoFingerGesture swiping with two fingers will also trigger the gesture. + + + + +## Callbacks + + + + +## Event data + +### Event attributes specific to `PanGesture`: + +### `translationX` + +Translation of the pan gesture along X axis accumulated over the time of the gesture. The value is expressed in the point units. + +### `translationY` + +Translation of the pan gesture along Y axis accumulated over the time of the gesture. The value is expressed in the point units. + +### `velocityX` + +Velocity of the pan gesture along the X axis in the current moment. The value is expressed in point units per second. + +### `velocityY` + +Velocity of the pan gesture along the Y axis in the current moment. The value is expressed in point units per second. + +### `x` + +X coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the [`GestureDetector`](./gesture-detector.md). Expressed in point units. + +### `y` + +Y coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the [`GestureDetector`](./gesture-detector.md). Expressed in point units. + +### `absoluteX` + +X coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. The value is expressed in point units. It is recommended to use it instead of [`x`](#x) in cases when the original view can be transformed as an effect of the gesture. + +### `absoluteY` + +Y coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. The value is expressed in point units. It is recommended to use it instead of [`y`](#y) in cases when the original view can be transformed as an effect of the gesture. + + + +## Example + +```jsx +const END_POSITION = 200; +const onLeft = useSharedValue(true); +const position = useSharedValue(0); + +const panGesture = Gesture.Pan() + .onUpdate((e) => { + if (onLeft.value) { + position.value = e.translationX; + } else { + position.value = END_POSITION + e.translationX; + } + }) + .onEnd((e) => { + if (position.value > END_POSITION / 2) { + position.value = withTiming(END_POSITION, { duration: 100 }); + onLeft.value = false; + } else { + position.value = withTiming(0, { duration: 100 }); + onLeft.value = true; + } + }); + +const animatedStyle = useAnimatedStyle(() => ({ + transform: [{ translateX: position.value }], +})); + +return ( + + + +); +``` diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/pinch-gesture.md b/docs/versioned_docs/version-2.4.0/api/gestures/pinch-gesture.md new file mode 100644 index 0000000000..5b56e7d043 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/pinch-gesture.md @@ -0,0 +1,77 @@ +--- +id: pinch-gesture +title: Pinch gesture +sidebar_label: Pinch gesture +--- + +import BaseEventData from './base-gesture-event-data.md'; +import BaseEventConfig from './base-gesture-config.md'; +import BaseContinousEventConfig from './base-continous-gesture-config.md'; +import BaseEventCallbacks from './base-gesture-callbacks.md'; +import BaseContinousEventCallbacks from './base-continous-gesture-callbacks.md'; + +A continuous gesture that recognizes pinch gesture. It allows for tracking the distance between two fingers and use that information to scale or zoom your content. +The gesture [activates](../../under-the-hood/states-events.md#active) when fingers are placed on the screen and change their position. +Gesture callback can be used for continuous tracking of the pinch gesture. It provides information about velocity, anchor (focal) point of gesture and scale. + +The 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 the two fingers increases, the scale factor increases proportionally. +Similarly, the scale factor decreases as the distance between the fingers decreases. +Pinch gestures are used most commonly to change the size of objects or content onscreen. +For example, map views use pinch gestures to change the zoom level of the map. + +## Config + + + + +## Callbacks + + + + +## Event data + +### Event attributes specific to `PinchGesture`: + +### `scale` + +The scale factor relative to the points of the two touches in screen coordinates. + +### `velocity` + +Velocity of the pan gesture the current moment. The value is expressed in point units per second. + +### `focalX` + +Position expressed in points along X axis of center anchor point of gesture + +### `focalY` + +Position expressed in points along Y axis of center anchor point of gesture + + + +## Example + +```jsx +const scale = useSharedValue(1); +const savedScale = useSharedValue(1); + +const pinchGesture = Gesture.Pinch() + .onUpdate((e) => { + scale.value = savedScale.value * e.scale; + }) + .onEnd(() => { + savedScale.value = scale.value; + }); + +const animatedStyle = useAnimatedStyle(() => ({ + transform: [{ scale: scale.value }], +})); + +return ( + + + +); +``` diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/rotation-gesture.md b/docs/versioned_docs/version-2.4.0/api/gestures/rotation-gesture.md new file mode 100644 index 0000000000..6550e0ea98 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/rotation-gesture.md @@ -0,0 +1,74 @@ +--- +id: rotation-gesture +title: Rotation gesture +sidebar_label: Rotation gesture +--- + +import BaseEventData from './base-gesture-event-data.md'; +import BaseEventConfig from './base-gesture-config.md'; +import BaseContinousEventConfig from './base-continous-gesture-config.md'; +import BaseEventCallbacks from './base-gesture-callbacks.md'; +import BaseContinousEventCallbacks from './base-continous-gesture-callbacks.md'; + +A continuous gesture that can recognize a rotation gesture and track its movement. + +The gesture [activates](../../under-the-hood/states-events.md#active) when fingers are placed on the screen and change position in a proper way. + +Gesture callback can be used for continuous tracking of the rotation gesture. It provides information about the gesture such as the amount rotated, the focal point of the rotation (anchor), and its instantaneous velocity. + +## Config + + + + +## Callbacks + + + + +## Event data + +### Event attributes specific to `RotationGesture`: + +### `rotation` + +Amount rotated, expressed in radians, from the gesture's focal point (anchor). + +### `velocity` + +Instantaneous velocity, expressed in point units per second, of the gesture. + +### `anchorX` + +X coordinate, expressed in points, of the gesture's central focal point (anchor). + +### `anchorY` + +Y coordinate, expressed in points, of the gesture's central focal point (anchor). + + + +## Example + +```jsx +const rotation = useSharedValue(1); +const savedRotation = useSharedValue(1); + +const rotationGesture = Gesture.Rotation() + .onUpdate((e) => { + rotation.value = savedRotation.value + e.rotation; + }) + .onEnd(() => { + savedRotation.value = rotation.value; + }); + +const animatedStyle = useAnimatedStyle(() => ({ + transform: [{ rotateZ: `${(rotation.value / Math.PI) * 180}deg` }], +})); + +return ( + + + +); +``` diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/state-manager.md b/docs/versioned_docs/version-2.4.0/api/gestures/state-manager.md new file mode 100644 index 0000000000..cb50e8212b --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/state-manager.md @@ -0,0 +1,26 @@ +--- +id: state-manager +title: Gesture state manager +sidebar_label: Gesture state manager +--- + +`GestureStateManager` allows to manually control the state of the gestures. Please note that `react-native-reanimated` is required to use it, since it allows for synchronously executing methods in worklets. + +## Methods + +### `begin()` + +Transition the gesture to the [`BEGAN`](../../under-the-hood/states-events.md#began) state. This method will have no effect if the gesture has already activated or finished. + +### `activate()` + +Transition the gesture to the [`ACTIVE`](../../under-the-hood/states-events.md#active) state. This method will have no effect if the handler is already active, or has finished. +If the gesture is [`exclusive`](../../gesture-composition) with another one, the activation will be delayed until the gesture with higher priority fails. + +### `end()` + +Transition the gesture to the [`END`](../../under-the-hood/states-events.md#end) state. This method will have no effect if the handler has already finished. + +### `fail()` + +Transition the gesture to the [`FAILED`](../../under-the-hood/states-events.md#failed) state. This method will have no effect if the handler has already finished. diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/tap-gesture.md b/docs/versioned_docs/version-2.4.0/api/gestures/tap-gesture.md new file mode 100644 index 0000000000..6c6c0a0872 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/tap-gesture.md @@ -0,0 +1,100 @@ +--- +id: tap-gesture +title: Tap gesture +sidebar_label: Tap gesture +--- + +import BaseEventData from './base-gesture-event-data.md'; +import BaseEventConfig from './base-gesture-config.md'; +import BaseEventCallbacks from './base-gesture-callbacks.md'; + +A discrete gesture that recognizes one or many taps. + +Tap gestures detect one or more fingers briefly touching the screen. +The fingers involved in these gestures must not move significantly from their initial touch positions. +The required number of taps and allowed distance from initial position may be configured. +For example, you might configure tap gesture recognizers to detect single taps, double taps, or triple taps. + +In order for a gesture to [activate](../../under-the-hood/states-events.md#active), specified gesture requirements such as minPointers, numberOfTaps, maxDist, maxDuration, and maxDelayMs (explained below) must be met. Immediately after the gesture [activates](../../under-the-hood/states-events.md#active), it will [end](../../under-the-hood/states-events.md#end). + +## Config + +### Properties specific to `TapGesture`: + +### `minPointers(value: number)` + +Minimum number of pointers (fingers) required to be placed before the gesture [activates](../../under-the-hood/states-events.md#active). Should be a positive integer. The default value is 1. + +### `maxDuration(value: number)` + +Maximum time, expressed in milliseconds, that defines how fast a finger must be released after a touch. The default value is 500. + +### `maxDelay(value: number)` + +Maximum time, expressed in milliseconds, that can pass before the next tap — if many taps are required. The default value is 500. + +### `numberOfTaps(value: number)` + +Number of tap gestures required to [activate](../../under-the-hood/states-events.md#active) the gesture. The default value is 1. + +### `maxDeltaX(value: number)` + +Maximum distance, expressed in points, that defines how far the finger is allowed to travel along the X axis during a tap gesture. If the finger travels further than the defined distance along the X axis and the gesture hasn't yet [activated](../../under-the-hood/states-events.md#active), it will fail to recognize the gesture. + +### `maxDeltaY(value: number)` + +Maximum distance, expressed in points, that defines how far the finger is allowed to travel along the Y axis during a tap gesture. If the finger travels further than the defined distance along the Y axis and the gesture hasn't yet [activated](../../under-the-hood/states-events.md#active), it will fail to recognize the gesture. + +### `maxDistance(value: number)` + +Maximum distance, expressed in points, that defines how far the finger is allowed to travel during a tap gesture. If the finger travels further than the defined distance and the gesture hasn't yet [activated](../../under-the-hood/states-events.md#active), it will fail to recognize the gesture. + + + +## Callbacks + + + +## Event data + +### Event attributes specific to `TapGesture`: + +### `x` + +X coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the [`GestureDetector`](./gesture-detector.md). + +### `y` + +Y coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the [`GestureDetector`](./gesture-detector.md). + +### `absoluteX` + +X coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. It is recommended to use `absoluteX` instead of [`x`](#x) in cases when the view attached to the [`GestureDetector`](./gesture-detector.md) can be transformed as an effect of the gesture. + +### `absoluteY` + +Y coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. It is recommended to use `absoluteY` instead of [`y`](#y) in cases when the view attached to the [`GestureDetector`](./gesture-detector.md) can be transformed as an effect of the gesture. + + + +## Example + +```jsx +const singleTap = Gesture.Tap() + .maxDuration(250) + .onStart(() => { + Alert.alert('Single tap!'); + }); + +const doubleTap = Gesture.Tap() + .maxDuration(250) + .onStart(() => { + Alert.alert('Double tap!'); + }); + +return ( + + + +); +``` diff --git a/docs/versioned_docs/version-2.4.0/api/gestures/touch-events.md b/docs/versioned_docs/version-2.4.0/api/gestures/touch-events.md new file mode 100644 index 0000000000..58103d7b25 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/gestures/touch-events.md @@ -0,0 +1,49 @@ +--- +id: touch-events +title: Touch events +sidebar_label: Touch events +--- + +### Touch event attributes: + +### `eventType` + +Type of the current event - whether the finger was placed on the screen, moved, lifted or cancelled. + +### `changedTouches` + +An array of objects where every object represents a single touch. Contains information only about the touches that were affected by the event i.e. those that were placed down, moved, lifted or cancelled. + +### `allTouches` + +An array of objects where every object represents a single touch. Contains information about all active touches. + +### `numberOfTouches` + +Number representing the count of currently active touches. + +:::caution +Don't rely on the order of items in the `touches` as it may change during the gesture, instead use the `id` attribute to track individual touches across events. +::: + +### PointerData attributes: + +### `id` + +A number representing id of the touch. It may be used to track the touch between events as the id will not change while it is being tracked. + +### `x` + +X coordinate of the current position of the touch relative to the view attached to the [`GestureDetector`](./gesture-detector.md). Expressed in point units. + +### `y` + +Y coordinate of the current position of the touch relative to the view attached to the [`GestureDetector`](./gesture-detector.md). Expressed in point units. + +### `absoluteX` + +X coordinate of the current position of the touch relative to the window. The value is expressed in point units. It is recommended to use it instead of [`x`](#x) in cases when the original view can be transformed as an effect of the gesture. + +### `absoluteY` + +Y coordinate of the current position of the touch relative to the window. The value is expressed in point units. It is recommended to use it instead of [`y`](#y) in cases when the original view can be transformed as an effect of the gesture. diff --git a/docs/versioned_docs/version-2.4.0/api/test-api.md b/docs/versioned_docs/version-2.4.0/api/test-api.md new file mode 100644 index 0000000000..2eacd0c711 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/api/test-api.md @@ -0,0 +1,108 @@ +--- +id: test-api +title: Testing +--- + +:::info +If you want to use `fireGestureHandler` and `getByGestureTestId`, you need to import them from `react-native-gesture-handler/jest-utils` package. +::: + +## fireGestureHandler(gestureOrHandler, eventList) + +Simulates one event stream (i.e. event sequence starting with `BEGIN` state and ending +with one of `END`/`FAIL`/`CANCEL` states), calling appropriate callbacks associated with given gesture handler. + +### Arguments + +#### `gestureOrHandler` + +Represents either: + +1. Gesture handler component found by Jest queries (e.g. `getByTestId`) +2. Gesture found by [`getByGestureTestId()`](#getbygestureidtestid) + +#### `eventList` + +Event data passed to appropriate callback. RNGH fills event list if required +data is missing using these rules: + +1. `oldState` is filled using state of the previous event. `BEGIN` events use + `UNDETERMINED` value as previous event. +2. Events after first `ACTIVE` state can omit `state` field. +3. Handler specific data is filled (e.g. `numberOfTouches`, `x` fields) with + defaults. +4. Missing `BEGIN` and `END` events are added with data copied from first and last + passed event, respectively. +5. If first event don't have `state` field, the `ACTIVE` state is assumed. + +Some examples: + +```jsx +const oldStateFilled = [ + { state: State.BEGAN }, + { state: State.ACTIVE }, + { state: State.END }, +]; // three events with specified state are fired. + +const implicitActiveState = [ + { state: State.BEGAN }, + { state: State.ACTIVE }, + { x: 5 }, + { state: State.END }, +]; // 4 events, including two ACTIVE events (second one has overriden additional data). + +const implicitBegin = [ + { x: 1, y: 11 }, + { x: 2, y: 12, state: State.FAILED }, +]; // 3 events, including implicit BEGAN, one ACTIVE, and one FAILED event with additional data. + +const implicitBeginAndEnd = [ + { x: 5, y: 15 }, + { x: 6, y: 16 }, + { x: 7, y: 17 }, +]; // 5 events, including 3 ACTIVE events and implicit BEGAN and END events. BEGAN uses first event's additional data, END uses last event's additional data. + +const allImplicits = []; // 3 events, one BEGIN, one ACTIVE, one END with defaults. +``` + +### Example + +Extracted from RNGH tests, check `Events.test.tsx` for full implementation. + +```tsx +it('sends events with additional data to handlers', () => { + const panHandlers = mockedEventHandlers(); + render(); + fireGestureHandler(getByGestureTestId('pan'), [ + { state: State.BEGAN, translationX: 0 }, + { state: State.ACTIVE, translationX: 10 }, + { translationX: 20 }, + { translationX: 20 }, + { state: State.END, translationX: 30 }, + ]); + + expect(panHandlers.active).toBeCalledTimes(3); + expect(panHandlers.active).toHaveBeenLastCalledWith( + expect.objectContaining({ translationX: 20 }) + ); +}); +``` + +## getByGestureTestId(testID) + +Returns opaque data type associated with gesture. Gesture is found via `testID` attribute in rendered +components (see [`withTestID` method](./gestures/base-gesture-config.md#withrefref)). + +### Arguments + +#### `testID` + +String identifying gesture. + +### Notes + +`testID` must be unique among components rendered in test. + +### Example + +See above example for `fireGestureHandler`. diff --git a/docs/versioned_docs/version-2.4.0/gesture-composition.md b/docs/versioned_docs/version-2.4.0/gesture-composition.md new file mode 100644 index 0000000000..e55e06fae6 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/gesture-composition.md @@ -0,0 +1,181 @@ +--- +id: gesture-composition +title: Composing gestures +sidebar_label: Composing gestures +--- + +Composing gestures is much simpler in RNGH2, you don't need to create a ref for every gesture that depends on another one. Instead you can use `Race`, `Simultaneous` and `Exclusive` methods provided by the `Gesture` object. + +## Race + +Only one of the provided gestures can become active at the same time. The first gesture to become active will cancel the rest of the gestures. It accepts variable number of arguments. +It is the equivalent to having more than one gesture handler without defining `simultaneousHandlers` and `waitFor` props. + +For example, lets say that you have a component that you want to make draggable but you also want to show additional options on long press. Presumably you would not want the component to move after the long press activates. You can accomplish this using `Race`: + +> Note: the `useSharedValue` and `useAnimatedStyle` are part of [`react-native-reanimated`](https://docs.swmansion.com/react-native-reanimated/). + +```js +const offset = useSharedValue({ x: 0, y: 0 }); +const start = useSharedValue({ x: 0, y: 0 }); +const popupPosition = useSharedValue({ x: 0, y: 0 }); +const popupAlpha = useSharedValue(0); + +const animatedStyles = useAnimatedStyle(() => { + return { + transform: [{ translateX: offset.value.x }, { translateY: offset.value.y }], + }; +}); + +const animatedPopupStyles = useAnimatedStyle(() => { + return { + transform: [ + { translateX: popupPosition.value.x }, + { translateY: popupPosition.value.y }, + ], + opacity: popupAlpha.value, + }; +}); + +const dragGesture = Gesture.Pan() + .onStart((_e) => { + popupAlpha.value = withTiming(0); + }) + .onUpdate((e) => { + offset.value = { + x: e.translationX + start.value.x, + y: e.translationY + start.value.y, + }; + }) + .onEnd(() => { + start.value = { + x: offset.value.x, + y: offset.value.y, + }; + }); + +const longPressGesture = Gesture.LongPress().onStart((_event) => { + popupPosition.value = { x: offset.value.x, y: offset.value.y }; + popupAlpha.value = withTiming(1); +}); + +const composed = Gesture.Race(dragGesture, longPressGesture); + +return ( + + + + + + +); +``` + +## Simultaneous + +All of the provided gestures can activate at the same time. Activation of one will not cancel the other. +It is the equivalent to having some gesture handlers, each with `simultaneousHandlers` prop set to the other handlers. + +For example, if you want to make a gallery app, you might want user to be able to zoom, rotate and pan around photos. You can do it with `Simultaneous`: + +> Note: the `useSharedValue` and `useAnimatedStyle` are part of [`react-native-reanimated`](https://docs.swmansion.com/react-native-reanimated/). + +```js +const offset = useSharedValue({ x: 0, y: 0 }); +const start = useSharedValue({ x: 0, y: 0 }); +const scale = useSharedValue(1); +const savedScale = useSharedValue(1); +const rotation = useSharedValue(0); +const savedRotation = useSharedValue(0); + +const animatedStyles = useAnimatedStyle(() => { + return { + transform: [ + { translateX: offset.value.x }, + { translateY: offset.value.y }, + { scale: scale.value }, + { rotateZ: `${rotation.value}rad` }, + ], + }; +}); + +const dragGesture = Gesture.Pan() + .averageTouches(true) + .onUpdate((e) => { + offset.value = { + x: e.translationX + start.value.x, + y: e.translationY + start.value.y, + }; + }) + .onEnd(() => { + start.value = { + x: offset.value.x, + y: offset.value.y, + }; + }); + +const zoomGesture = Gesture.Pinch() + .onUpdate((event) => { + scale.value = savedScale.value * event.scale; + }) + .onEnd(() => { + savedScale.value = scale.value; + }); + +const rotateGesture = Gesture.Rotation() + .onUpdate((event) => { + rotation.value = savedRotation.value + event.rotation; + }) + .onEnd(() => { + savedRotation.value = rotation.value; + }); + +const composed = Gesture.Simultaneous( + dragGesture, + Gesture.Simultaneous(zoomGesture, rotateGesture) +); + +return ( + + + + + +); +``` + +## Exclusive + +Only one of the provided gestures can become active, with the first one having a higher priority than the second one (if both gestures are still possible, the second one will wait for the first one to fail before it activates), second one having a higher priority than the third one, and so on. +It is equivalent to having some gesture handlers where the second one has the `waitFor` prop set to the first handler, third one has the `waitFor` prop set to the first and the second one, and so on. + +For example, if you want to make a component that responds to single tap as well as to a double tap, you can accomplish that using `Exclusive`: + +> Note: the `useSharedValue` and `useAnimatedStyle` are part of [`react-native-reanimated`](https://docs.swmansion.com/react-native-reanimated/). + +```js +const singleTap = Gesture.Tap().onEnd((_event, success) => { + if (success) { + console.log('single tap!'); + } +}); +const doubleTap = Gesture.Tap() + .numberOfTaps(2) + .onEnd((_event, success) => { + if (success) { + console.log('double tap!'); + } + }); + +const taps = Gesture.Exclusive(doubleTap, singleTap); + +return ( + + + +); +``` + +## Composition vs `simultaneousWithExternalGesture` and `requireExternalGestureToFail` + +You may have noticed that gesture composition described above requires you to mount all of the composed gestures under a single `GestureDetector`, effectively attaching them to the same underlying component. If you want to make a relation between gestures that are attached to separate `GestureDetectors`, we have a separate mechanism for that: `simultaneousWithExternalGesture` and `requireExternalGestureToFail` methods that are available on every base gesture. They work exactly the same way as `simultaneousHandlers` and `waitFor` on gesture handlers, that is they just mark the relation between the gestures without joining them into single object. diff --git a/docs/versioned_docs/version-2.4.0/gesture-handlers/api/common-gh.md b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/common-gh.md new file mode 100644 index 0000000000..450dc7f853 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/common-gh.md @@ -0,0 +1,93 @@ +--- +id: common-gh +title: Common handler properties +sidebar_label: Common handler properties +--- + +:::info +We recently released RNGH 2.0 with new Gestures system. Check out [RNGH 2.0 +section in Introduction](../../introduction.md#rngh-20) for more information. +::: + +This page covers the common set of properties all gesture handler components expose. + +### Units + +All handler component properties and event attributes that represent onscreen dimensions are expressed in screen density independent units we refer to as "points". +These are the units commonly used in React Native ecosystem (e.g. in the [layout system](http://facebook.github.io/react-native/docs/flexbox.html)). +They do not map directly to physical pixels but instead to [iOS's points](https://developer.apple.com/library/content/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html#//apple_ref/doc/uid/TP40010156-CH14-SW7) and to [dp](https://developer.android.com/guide/topics/resources/more-resources#Dimension) units on Android. + +## Properties + +This section describes properties that can be used with all gesture handler components: + +### `enabled` + +Accepts a boolean value. +Indicates whether the given handler should be analyzing stream of touch events or not. +When set to `false` we can be sure that the handler's state will **never** become [`ACTIVE`](../basics/state.md#active). +If the value gets updated while the handler already started recognizing a gesture, then the handler's state it will immediately change to [`FAILED`](../basics/state.md#failed) or [`CANCELLED`](../basics/state.md#cancelled) (depending on its current state). +Default value is `true`. + +### `shouldCancelWhenOutside` + +Accepts a boolean value. +When `true` the handler will [cancel](../basics/state.md#cancelled) or [fail](../basics/state.md#failed) recognition (depending on its current state) whenever the finger leaves the area of the connected view. +Default value of this property is different depending on the handler type. +Most handlers' `shouldCancelWhenOutside` property defaults to `false` except for the [`LongPressGestureHandler`](./longpress-gh.md) and [`TapGestureHandler`](./tap-gh.md) which default to `true`. + +### `cancelsTouchesInView` (**iOS only**) + +Accepts a boolean value. +When `true`, the handler will cancel touches for native UI components (`UIButton`, `UISwitch`, etc) it's attached to when it becomes [`ACTIVE`](../basics/state.md#active). +Default value is `true`. + +### `simultaneousHandlers` + +Accepts a react ref object or an array of refs to other handler components (refs should be created using [`React.createRef()`](https://reactjs.org/docs/refs-and-the-dom.html)). When set, the handler will be allowed to [activate](../basics/state.md#active) even if one or more of the handlers provided by their refs are in an [`ACTIVE`](../basics/state.md#active) state. It will also prevent the provided handlers from [cancelling](../basics/state.md#cancelled) the current handler when they [activate](../basics/state.md#active). Read more in the [cross handler interaction](../basics/interactions.md#simultaneous-recognition) section. + +### `waitFor` + +Accepts a react ref object or an array of refs to other handler components (refs should be created using [`React.createRef()`](https://reactjs.org/docs/refs-and-the-dom.html)). When set the handler will not [activate](../basics/state.md#active) as long as the handlers provided by their refs are in the [`BEGAN`](../basics/state.md#began) state. Read more in the [cross handler interaction](../basics/interactions.md#awaiting-other-handlers) section. + +### `hitSlop` + +This parameter enables control over what part of the connected view area can be used to [begin](../basics/state.md#began) recognizing the gesture. +When a negative number is provided the bounds of the view will reduce the area by the given number of points in each of the sides evenly. + +Instead you can pass an object to specify how each boundary side should be reduced by providing different number of points for `left`, `right`, `top` or `bottom` sides. +You can alternatively provide `horizontal` or `vertical` instead of specifying directly `left`, `right` or `top` and `bottom`. +Finally, the object can also take `width` and `height` attributes. +When `width` is set it is only allow to specify one of the sides `right` or `left`. +Similarly when `height` is provided only `top` or `bottom` can be set. +Specifying `width` or `height` is useful if we only want the gesture to activate on the edge of the view. In which case for example we can set `left: 0` and `width: 20` which would make it possible for the gesture to be recognize when started no more than 20 points from the left edge. + +**IMPORTANT:** Note that this parameter is primarily designed to reduce the area where gesture can activate. Hence it is only supported for all the values (except `width` and `height`) to be non positive (0 or lower). Although on Android it is supported for the values to also be positive and therefore allow to expand beyond view bounds but not further than the parent view bounds. To achieve this effect on both platforms you can use React Native's View [hitSlop](https://facebook.github.io/react-native/docs/view.html#props) property. + +### `onGestureEvent` + +Takes a callback that is going to be triggered for each subsequent touch event while the handler is in an [ACTIVE](../basics/state.md#active) state. Event payload depends on the particular handler type. Common set of event data attributes is documented [below](#event-data) and handler specific attributes are documented on the corresponding handler pages. E.g. event payload for [`PinchGestureHandler`](./rotation-gh.md#event-data) contains `scale` attribute that represents how the distance between fingers changed since when the gesture started. + +Instead of a callback [`Animated.event`](https://facebook.github.io/react-native/docs/animated.html#event) object can be used. Also Animated events with `useNativeDriver` flag enabled **are fully supported**. + +### `onHandlerStateChange` + +Takes a callback that is going to be triggered when [state](../basics/state.md) of the given handler changes. + +The event payload contains the same payload as in case of [`onGestureEvent`](#ongestureevent) including handler specific event attributes some handlers may provide. + +In addition `onHandlerStateChange` event payload contains `oldState` attribute which represents the [state](../basics/state.md) of the handler right before the change. + +Instead of a callback [`Animated.event`](https://facebook.github.io/react-native/docs/animated.html#event) object can be used. Also Animated events with `useNativeDriver` flag enabled **are fully supported**. + +## Event data + +This section describes the attributes of event object being provided to [`onGestureEvent`](#ongestureevent) and [`onHandlerStateChange`](#onhandlerstatechange) callbacks: + +### `state` + +Current [state](../basics/state.md) of the handler. Expressed as one of the constants exported under `State` object by the library. Refer to the section about [handler state](../basics/state.md) to learn more about how to use it. + +### `numberOfPointers` + +Represents the number of pointers (fingers) currently placed on the screen. diff --git a/docs/versioned_docs/version-2.4.0/gesture-handlers/api/create-native-wrapper.md b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/create-native-wrapper.md new file mode 100644 index 0000000000..c8c8be2fe4 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/create-native-wrapper.md @@ -0,0 +1,27 @@ +--- +id: create-native-wrapper +title: createNativeWrapper +sidebar_label: createNativeWrapper() +--- + +:::info +We recently released RNGH 2.0 with new Gestures system. Check out [RNGH 2.0 +section in Introduction](../../introduction.md#rngh-20) for more information. +::: + +Creates provided component with NativeViewGestureHandler, allowing it to be part of RNGH's +gesture system. + +## Arguments + +### Component + +The component we want to wrap. + +### config + +Config is an object with properties that can be used on [`NativeViewGestureHandler`](./nativeview-gh.md) + +## Returns + +Wrapped component. diff --git a/docs/versioned_docs/version-2.4.0/gesture-handlers/api/fling-gh.md b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/fling-gh.md new file mode 100644 index 0000000000..89f339f191 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/fling-gh.md @@ -0,0 +1,76 @@ +--- +id: fling-gh +title: FlingGestureHandler +sidebar_label: Fling +--- + +:::info +We recently released RNGH 2.0 with new Gestures system. Check out [RNGH 2.0 +section in Introduction](../../introduction.md#rngh-20) for more information. +::: + +A discrete gesture handler that activates when the movement is sufficiently long and fast. +Handler gets [ACTIVE](../basics/state#active) when movement is sufficiently long and it does not take too much time. +When handler gets activated it will turn into [END](../basics/state#end) state when finger is released. +The handler will fail to recognize if the finger is lifted before being activated. +The handler is implemented using [UISwipeGestureRecognizer](https://developer.apple.com/documentation/uikit/uiswipegesturerecognizer) on iOS and from scratch on Android. + +## Properties + +See [set of properties inherited from base handler class](./common-gh.md#properties). Below is a list of properties specific to `FlingGestureHandler` component: + +### `direction` + +Expressed allowed direction of movement. It's possible to pass one or many directions in one parameter: + +```js +direction={Directions.RIGHT | Directions.LEFT} +``` + +or + +```js +direction={Directions.DOWN} +``` + +### `numberOfPointers` + +Determine exact number of points required to handle the fling gesture. + +## Event data + +See [set of event attributes from base handler class](./common-gh.md#event-data). Below is a list of gesture event attributes specific to `FlingGestureHandler`: + +### `x` + +X coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the handler. Expressed in point units. + +### `y` + +Y coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the handler. Expressed in point units. + +### `absoluteX` + +X coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. The value is expressed in point units. It is recommended to use it instead of [`x`](#x) in cases when the original view can be transformed as an effect of the gesture. + +### `absoluteY` + +Y coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. The value is expressed in point units. It is recommended to use it instead of [`y`](#y) in cases when the original view can be transformed as an effect of the gesture. + +## Example + +See the [fling example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/release_tests/fling/index.tsx) from Gesture Handler Example App. + +```js +const LongPressButton = () => ( + { + if (nativeEvent.state === State.ACTIVE) { + Alert.alert("I'm flinged!"); + } + }}> + + +); +``` diff --git a/docs/versioned_docs/version-2.4.0/gesture-handlers/api/force-gh.md b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/force-gh.md new file mode 100644 index 0000000000..3fc017e69e --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/force-gh.md @@ -0,0 +1,67 @@ +--- +id: force-gh +title: ForceTouchGestureHandler (iOS only) +sidebar_label: Force touch +--- + +:::info +We recently released RNGH 2.0 with new Gestures system. Check out [RNGH 2.0 +section in Introduction](../../introduction.md#rngh-20) for more information. +::: + +A continuous gesture handler that recognizes force of a touch. It allows for tracking pressure of touch on some iOS devices. +The handler [activates](../basics/state.md#active) when pressure of touch if greater or equal than `minForce`. It fails if pressure is greater than `maxForce` +Gesture callback can be used for continuous tracking of the touch pressure. It provides information for one finger (the first one). + +At the beginning of the gesture, the pressure factor is 0.0. As the pressure increases, the pressure factor increases proportionally. The maximum pressure is 1.0. + +The handler is implemented using custom [UIGestureRecognizer](https://developer.apple.com/documentation/uikit/uigesturerecognizer) on iOS. There's no implementation provided on Android and it simply render children without any wrappers. +Since this behaviour is only provided on some iOS devices, this handler should not be used for defining any crucial behaviors. Use it only as an additional improvement and make all features to be accessed without this handler as well. + +# Properties + +See [set of properties inherited from base handler class](./common-gh.md#properties). Below is a list of properties specific to `ForceTouchGestureHandler` component: + +### `minForce` + +A minimal pressure that is required before handler can [activate](../basics/state.md#active). Should be a value from range `[0.0, 1.0]`. Default is `0.2`. + +### `maxForce` + +A maximal pressure that could be applied for handler. If the pressure is greater, handler [fails](../basics/state.md#failed). Should be a value from range `[0.0, 1.0]`. + +### `feedbackOnActivation` + +Boolean value defining if haptic feedback has to be performed on activation. + +## Event data + +See [set of event attributes from base handler class](./common-gh.md#event-data). Below is a list of gesture event attributes specific to `ForceTouchGestureHandler`: + +### `force` + +The pressure of a touch. + +## Static method + +### `forceTouchAvailable` + +You may check if it's possible to use `ForceTouchGestureHandler` with `ForceTouchGestureHandler.forceTouchAvailable` + +## Example + +See the [force touch handler example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/basic/forcetouch/index.tsx) from Gesture Handler Example App. + +```js + + + +``` diff --git a/docs/versioned_docs/version-2.4.0/gesture-handlers/api/longpress-gh.md b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/longpress-gh.md new file mode 100644 index 0000000000..213255e1de --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/longpress-gh.md @@ -0,0 +1,70 @@ +--- +id: longpress-gh +title: LongPressGestureHandler +sidebar_label: Long press +--- + +:::info +We recently released RNGH 2.0 with new Gestures system. Check out [RNGH 2.0 +section in Introduction](../../introduction.md#rngh-20) for more information. +::: + +A discrete gesture handler that activates when the corresponding view is pressed for a sufficiently long time. +This handler's state will turn into [END](../basics/state.md#end) immediately after the finger is released. +The handler will fail to recognize a touch event if the finger is lifted before the [minimum required time](#mindurationms) or if the finger is moved further than the [allowable distance](#maxdist). + +The handler is implemented using [UILongPressGestureRecognizer](https://developer.apple.com/documentation/uikit/uilongpressgesturerecognizer) on iOS and [LongPressGestureHandler](https://github.com/software-mansion/react-native-gesture-handler/blob/main/android/lib/src/main/java/com/swmansion/gesturehandler/LongPressGestureHandler.java) on Android. + +## Properties + +See [set of properties inherited from base handler class](./common-gh.md#properties). Below is a list of properties specific to the `LongPressGestureHandler` component: + +### `minDurationMs` + +Minimum time, expressed in milliseconds, that a finger must remain pressed on the corresponding view. The default value is 500. + +### `maxDist` + +Maximum distance, expressed in points, that defines how far the finger is allowed to travel during a long press gesture. If the finger travels further than the defined distance and the handler hasn't yet [activated](../basics/state.md#active), it will fail to recognize the gesture. The default value is 10. + +## Event data + +See [set of event attributes from base handler class](./common-gh.md#event-data). Below is a list of gesture event attributes specific to the `LongPressGestureHandler` component: + +### `x` + +X coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the handler. + +### `y` + +Y coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the handler. + +### `absoluteX` + +X coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. It is recommended to use `absoluteX` instead of [`x`](#x) in cases when the view attached to the handler can be transformed as an effect of the gesture. + +### `absoluteY` + +Y coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. It is recommended to use `absoluteY` instead of [`y`](#y) in cases when the view attached to the handler can be transformed as an effect of the gesture. + +### `duration` + +Duration of the long press (time since the start of the event), expressed in milliseconds. + +## Example + +See the [multitap example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/basic/multitap/index.tsx) from GestureHandler Example App. + +```js +const LongPressButton = () => ( + { + if (nativeEvent.state === State.ACTIVE) { + Alert.alert("I'm being pressed for so long"); + } + }} + minDurationMs={800}> + + +); +``` diff --git a/docs/versioned_docs/version-2.4.0/gesture-handlers/api/nativeview-gh.md b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/nativeview-gh.md new file mode 100644 index 0000000000..aef1ac5398 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/nativeview-gh.md @@ -0,0 +1,27 @@ +--- +id: nativeview-gh +title: NativeViewGestureHandler +sidebar_label: NativeView +--- + +:::info +We recently released RNGH 2.0 with new Gestures system. Check out [RNGH 2.0 +section in Introduction](../../introduction.md#rngh-20) for more information. +::: + +A gesture handler that allows other touch handling components to participate in +RNGH's gesture system. + +Used by [`createNativeWrapper()`](./create-native-wrapper.md). + +## Properties + +See [set of properties inherited from base handler class](./common-gh.md#properties). Below is a list of properties specific to `NativeViewGestureHandler` component: + +### `shouldActivateOnStart` (**Android only**) + +When `true`, underlying handler will activate unconditionally when in `BEGAN` or `UNDETERMINED` state. + +### `disallowInterruption` + +When `true`, cancels all other gesture handlers when this `NativeViewGestureHandler` receives an `ACTIVE` state event. diff --git a/docs/versioned_docs/version-2.4.0/gesture-handlers/api/pan-gh.md b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/pan-gh.md new file mode 100644 index 0000000000..adb927371b --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/pan-gh.md @@ -0,0 +1,227 @@ +--- +id: pan-gh +title: PanGestureHandler +sidebar_label: Pan +--- + +:::info +We recently released RNGH 2.0 with new Gestures system. Check out [RNGH 2.0 +section in Introduction](../../introduction.md#rngh-20) for more information. +::: + +A continuous gesture handler that can recognize a panning (dragging) gesture and track its movement. + +The handler [activates](../basics/state.md#active) when a finger is placed on the screen and moved some initial distance. + +Configurations such as a minimum initial distance, specific vertical or horizontal pan detection and [number of fingers](#minPointers) required for activation (allowing for multifinger swipes) may be specified. + +Gesture callback can be used for continuous tracking of the pan gesture. It provides information about the gesture such as its XY translation from the starting point as well as its instantaneous velocity. + +The handler is implemented using [UIPanGestureRecognizer](https://developer.apple.com/documentation/uikit/uipangesturerecognizer) on iOS and [PanGestureHandler](https://github.com/software-mansion/react-native-gesture-handler/blob/main/android/lib/src/main/java/com/swmansion/gesturehandler/PanGestureHandler.java) on Android. + +## Custom activation criteria + +The `PanGestureHandler` component exposes a number of properties that can be used to customize the criteria under which a handler will [activate](../basics/state.md#active) or [fail](../basics/state.md#fail) when recognizing a gesture. + +When more than one of such a property is set, `PanGestureHandler` expects all criteria to be met for successful recognition and at most one of the criteria to be overstepped to fail recognition. +For example when both [`minDeltaX`](#mindeltax) and [`minDeltaY`](#mindeltay) are set to 20 we expect the finger to travel by 20 points in both the X and Y axis before the handler activates. +Another example would be setting both [`maxDeltaX`](#maxdeltaX) and [`maxDeltaY`](#maxdeltay) to 20 and [`minDist`](#mindist) to 23. +In such a case, if we move a finger along the X-axis by 20 points and along the Y-axis by 0 points, the handler will fail even though the finger is still within the bounds of translation along Y-axis. + +## Multi touch pan handling + +If your app relies on multi touch pan handling this section provides some information how the default behavior differs between the platform and how (if necessary) it can be unified. + +The difference in multi touch pan handling lies in the way how translation properties during the event are being calculated. +On iOS the default behavior when more than one finger is placed on the screen is to treat this situation as if only one pointer was placed in the center of mass (average position of all the pointers). +This applies also to many platform native components that handle touch even if not primarily interested in multi touch interactions like for example UIScrollView component. + +The default behavior for native components like scroll view, pager views or drawers is different and hence gesture handler defaults to that when it comes to pan handling. +The difference is that instead of treating the center of mass of all the fingers placed as a leading pointer it takes the latest placed finger as such. +This behavior can be changed on Android using [`avgTouches`](#avgtouches-android-only) flag. + +Note that on both Android and iOS when the additional finger is placed on the screen that translation prop is not affected even though the position of the pointer being tracked might have changed. +Therefore it is safe to rely on translation most of the time as it only reflects the movement that happens regardless of how many fingers are placed on the screen and if that number changes over time. +If you wish to track the "center of mass" virtual pointer and account for its changes when the number of finger changes you can use relative or absolute position provided in the event ([`x`](#x) and [`y`](#y) or [`absoluteX`](#absolutex) and [`absoluteY`](#absolutey)). + +## Properties + +See [set of properties inherited from base handler class](./common-gh.md#properties). Below is a list of properties specific to `PanGestureHandler` component: + +### `minDist` + +Minimum distance the finger (or multiple finger) need to travel before the handler [activates](../basics/state.md#active). Expressed in points. + +### `minPointers` + +A number of fingers that is required to be placed before handler can [activate](../basics/state.md#active). Should be a higher or equal to 0 integer. + +### `maxPointers` + +When the given number of fingers is placed on the screen and handler hasn't yet [activated](../basics/state.md#active) it will fail recognizing the gesture. Should be a higher or equal to 0 integer. + +### `activeOffsetX` + +Range along X axis (in points) where fingers travels without activation of handler. Moving outside of this range implies activation of handler. Range can be given as an array or a single number. +If range is set as an array, first value must be lower or equal to 0, a the second one higher or equal to 0. +If only one number `p` is given a range of `(-inf, p)` will be used if `p` is higher or equal to 0 and `(-p, inf)` otherwise. + +### `activeOffsetY` + +Range along Y axis (in points) where fingers travels without activation of handler. Moving outside of this range implies activation of handler. Range can be given as an array or a single number. +If range is set as an array, first value must be lower or equal to 0, a the second one higher or equal to 0. +If only one number `p` is given a range of `(-inf, p)` will be used if `p` is higher or equal to 0 and `(-p, inf)` otherwise. + +### `failOffsetY` + +When the finger moves outside this range (in points) along Y axis and handler hasn't yet activated it will fail recognizing the gesture. Range can be given as an array or a single number. +If range is set as an array, first value must be lower or equal to 0, a the second one higher or equal to 0. +If only one number `p` is given a range of `(-inf, p)` will be used if `p` is higher or equal to 0 and `(-p, inf)` otherwise. + +### `failOffsetX` + +When the finger moves outside this range (in points) along X axis and handler hasn't yet activated it will fail recognizing the gesture. Range can be given as an array or a single number. +If range is set as an array, first value must be lower or equal to 0, a the second one higher or equal to 0. +If only one number `p` is given a range of `(-inf, p)` will be used if `p` is higher or equal to 0 and `(-p, inf)` otherwise. + +### `maxDeltaX` + +> This method is deprecated but supported for backward compatibility. Instead of using `maxDeltaX={N}` you can do `failOffsetX={[-N, N]}`. + +When the finger travels the given distance expressed in points along X axis and handler hasn't yet [activated](../basics/state.md#active) it will fail recognizing the gesture. + +### `maxDeltaY` + +> This method is deprecated but supported for backward compatibility. Instead of using `maxDeltaY={N}` you can do `failOffsetY={[-N, N]}`. + +When the finger travels the given distance expressed in points along Y axis and handler hasn't yet [activated](../basics/state.md#active) it will fail recognizing the gesture. + +### `minOffsetX` + +> This method is deprecated but supported for backward compatibility. Instead of using `minOffsetX={N}` you can do `activeOffsetX={N}`. + +Minimum distance along X (in points) axis the finger (or multiple finger) need to travel before the handler [activates](../basics/state.md#active). If set to a lower or equal to 0 value we expect the finger to travel "left" by the given distance. When set to a higher or equal to 0 number the handler will activate on a movement to the "right". If you wish for the movement direction to be ignored use [`minDeltaX`](#mindeltax) instead. + +### `minOffsetY` + +> This method is deprecated but supported for backward compatibility. Instead of using `minOffsetY={N}` you can do `activeOffsetY={N}`. + +Minimum distance along Y (in points) axis the finger (or multiple finger) need to travel before the handler [activates](../basics/state.md#active). If set to a lower or equal to 0 value we expect the finger to travel "up" by the given distance. When set to a higher or equal to 0 number the handler will activate on a movement to the "bottom". If you wish for the movement direction to be ignored use [`minDeltaY`](#mindeltay) instead. + +### `minDeltaX` + +> This method is deprecated but supported for backward compatibility. Instead of using `minDeltaX={N}` you can do `activeOffsetX={[-N, N]}`. + +Minimum distance along X (in points) axis the finger (or multiple finger) need to travel (left or right) before the handler [activates](../basics/state.md#active). Unlike [`minoffsetx`](#minoffsetx) this parameter accepts only non-lower or equal to 0 numbers that represents the distance in point units. If you want for the handler to [activate](../basics/state.md#active) for the movement in one particular direction use [`minOffsetX`](#minoffsetx) instead. + +### `minDeltaY` + +> This method is deprecated but supported for backward compatibility. Instead of using `minDeltaY={N}` you can do `activeOffsetY={[-N, N]}`. + +Minimum distance along Y (in points) axis the finger (or multiple finger) need to travel (top or bottom) before the handler [activates](../basics/state.md#active). Unlike [`minOffsetY`](#minoffsety) this parameter accepts only non-lower or equal to 0 numbers that represents the distance in point units. If you want for the handler to [activate](../basics/state.md#active) for the movement in one particular direction use [`minOffsetY`](#minoffsety) instead. + +### `avgTouches` (Android only) + +### `enableTrackpadTwoFingerGesture` (iOS only) + +Enables two-finger gestures on supported devices, for example iPads with trackpads. If not enabled the gesture will require click + drag, with enableTrackpadTwoFingerGesture swiping with two fingers will also trigger the gesture. + +## Event data + +See [set of event attributes from base handler class](./common-gh.md#event-data). Below is a list of gesture event attributes specific to `PanGestureHandler`: + +### `translationX` + +Translation of the pan gesture along X axis accumulated over the time of the gesture. The value is expressed in the point units. + +### `translationY` + +Translation of the pan gesture along Y axis accumulated over the time of the gesture. The value is expressed in the point units. + +### `velocityX` + +Velocity of the pan gesture along the X axis in the current moment. The value is expressed in point units per second. + +### `velocityY` + +Velocity of the pan gesture along the Y axis in the current moment. The value is expressed in point units per second. + +### `x` + +X coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the handler. Expressed in point units. + +### `y` + +Y coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the handler. Expressed in point units. + +### `absoluteX` + +X coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. The value is expressed in point units. It is recommended to use it instead of [`x`](#x) in cases when the original view can be transformed as an effect of the gesture. + +### `absoluteY` + +Y coordinate of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. The value is expressed in point units. It is recommended to use it instead of [`y`](#y) in cases when the original view can be transformed as an effect of the gesture. + +## Example + +See the [draggable example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/basic/draggable/index.tsx) from Gesture Handler Example App. + +```js +import React, { Component } from 'react'; +import { Animated, Dimensions } from 'react-native'; +import { + GestureHandlerRootView, + PanGestureHandler, +} from 'react-native-gesture-handler'; + +const { width } = Dimensions.get('screen'); +const circleRadius = 30; + +class Circle extends Component { + _touchX = new Animated.Value(width / 2 - circleRadius); + + _onPanGestureEvent = Animated.event([{ nativeEvent: { x: this._touchX } }], { + useNativeDriver: true, + }); + + render() { + return ( + + + + + + + + ); + } +} + +export default function App() { + return ; +} +``` diff --git a/docs/versioned_docs/version-2.4.0/gesture-handlers/api/pinch-gh.md b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/pinch-gh.md new file mode 100644 index 0000000000..ac8c9b357c --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/pinch-gh.md @@ -0,0 +1,89 @@ +--- +id: pinch-gh +title: PinchGestureHandler +sidebar_label: Pinch +--- + +:::info +We recently released RNGH 2.0 with new Gestures system. Check out [RNGH 2.0 +section in Introduction](../../introduction.md#rngh-20) for more information. +::: + +A continuous gesture handler that recognizes pinch gesture. It allows for tracking the distance between two fingers and use that information to scale or zoom your content. +The handler [activates](../basics/state.md#active) when fingers are placed on the screen and change their position. +Gesture callback can be used for continuous tracking of the pinch gesture. It provides information about velocity, anchor (focal) point of gesture and scale. + +The 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 the two fingers increases, the scale factor increases proportionally. +Similarly, the scale factor decreases as the distance between the fingers decreases. +Pinch gestures are used most commonly to change the size of objects or content onscreen. +For example, map views use pinch gestures to change the zoom level of the map. + +The handler is implemented using [UIPinchGestureRecognizer](https://developer.apple.com/documentation/uikit/uipinchgesturerecognizer) on iOS and from scratch on Android. + +## Properties + +Properties provided to `PinchGestureHandler` do not extend [common set of properties from base handler class](./common-gh.md#properties). + +## Event data + +See [set of event attributes from base handler class](./common-gh.md#event-data). Below is a list of gesture event attributes specific to `PinchGestureHandler`: + +### `scale` + +The scale factor relative to the points of the two touches in screen coordinates. + +### `velocity` + +Velocity of the pan gesture the current moment. The value is expressed in point units per second. + +### `focalX` + +Position expressed in points along X axis of center anchor point of gesture + +### `focalY` + +Position expressed in points along Y axis of center anchor point of gesture + +## Example + +See the [scale and rotation example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/recipes/scaleAndRotate/index.tsx) from Gesture Handler Example App. + +```js +export class PinchableBox extends React.Component { + _baseScale = new Animated.Value(1); + _pinchScale = new Animated.Value(1); + _scale = Animated.multiply(this._baseScale, this._pinchScale); + _lastScale = 1; + _onPinchGestureEvent = Animated.event( + [{ nativeEvent: { scale: this._pinchScale } }], + { useNativeDriver: USE_NATIVE_DRIVER } + ); + + _onPinchHandlerStateChange = (event) => { + if (event.nativeEvent.oldState === State.ACTIVE) { + this._lastScale *= event.nativeEvent.scale; + this._baseScale.setValue(this._lastScale); + this._pinchScale.setValue(1); + } + }; + + render() { + return ( + + + + + + ); + } +} +``` diff --git a/docs/versioned_docs/version-2.4.0/gesture-handlers/api/rotation-gh.md b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/rotation-gh.md new file mode 100644 index 0000000000..b5dde52b55 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/rotation-gh.md @@ -0,0 +1,84 @@ +--- +id: rotation-gh +title: RotationGestureHandler +sidebar_label: Rotation +--- + +:::info +We recently released RNGH 2.0 with new Gestures system. Check out [RNGH 2.0 +section in Introduction](../../introduction.md#rngh-20) for more information. +::: + +A continuous gesture handler that can recognize a rotation gesture and track its movement. + +The handler [activates](../basics/state.md#active) when fingers are placed on the screen and change position in a proper way. + +Gesture callback can be used for continuous tracking of the rotation gesture. It provides information about the gesture such as the amount rotated, the focal point of the rotation (anchor), and its instantaneous velocity. + +The handler is implemented using [UIRotationGestureRecognizer](https://developer.apple.com/documentation/uikit/uirotationgesturerecognizer) on iOS and from scratch on Android. + +## Properties + +Properties provided to `RotationGestureHandler` do not extend [common set of properties from base handler class](./common-gh.md#properties). + +## Event data + +See [set of event attributes from base handler class](./common-gh.md#event-data). Below is a list of gesture event attributes specific to `RotationGestureHandler`: + +### `rotation` + +Amount rotated, expressed in radians, from the gesture's focal point (anchor). + +### `velocity` + +Instantaneous velocity, expressed in point units per second, of the gesture. + +### `anchorX` + +X coordinate, expressed in points, of the gesture's central focal point (anchor). + +### `anchorY` + +Y coordinate, expressed in points, of the gesture's central focal point (anchor). + +## Example + +See the [scale and rotation example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/recipes/scaleAndRotate/index.tsx) from Gesture Handler Example App. + +```js +class RotableBox extends React.Component { + _rotate = new Animated.Value(0); + _rotateStr = this._rotate.interpolate({ + inputRange: [-100, 100], + outputRange: ['-100rad', '100rad'], + }); + _lastRotate = 0; + _onRotateGestureEvent = Animated.event( + [{ nativeEvent: { rotation: this._rotate } }], + { useNativeDriver: USE_NATIVE_DRIVER } + ); + _onRotateHandlerStateChange = (event) => { + if (event.nativeEvent.oldState === State.ACTIVE) { + this._lastRotate += event.nativeEvent.rotation; + this._rotate.setOffset(this._lastRotate); + this._rotate.setValue(0); + } + }; + render() { + return ( + + + + ); + } +} +``` diff --git a/docs/versioned_docs/version-2.4.0/gesture-handlers/api/tap-gh.md b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/tap-gh.md new file mode 100644 index 0000000000..9eebabe7ba --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/gesture-handlers/api/tap-gh.md @@ -0,0 +1,92 @@ +--- +id: tap-gh +title: TapGestureHandler +sidebar_label: Tap +--- + +:::info +We recently released RNGH 2.0 with new Gestures system. Check out [RNGH 2.0 +section in Introduction](../../introduction.md#rngh-20) for more information. +::: + +A discrete gesture handler that recognizes one or many taps. + +Tap gestures detect one or more fingers briefly touching the screen. +The fingers involved in these gestures must not move significantly from their initial touch positions. +The required number of taps and allowed distance from initial position may be configured. +For example, you might configure tap gesture recognizers to detect single taps, double taps, or triple taps. + +In order for a handler to [activate](../basics/state.md#active), specified gesture requirements such as minPointers, numberOfTaps, maxDist, maxDurationMs, and maxDelayMs (explained below) must be met. Immediately after the handler [activates](../basics/state.md#active), it will [END](../basics/state.md#end). + +## Properties + +See [set of properties inherited from base handler class](./common-gh.md#properties). Below is a list of properties specific to the `TapGestureHandler` component: + +### `minPointers` + +Minimum number of pointers (fingers) required to be placed before the handler [activates](../basics/state.md#active). Should be a positive integer. The default value is 1. + +### `maxDurationMs` + +Maximum time, expressed in milliseconds, that defines how fast a finger must be released after a touch. The default value is 500. + +### `maxDelayMs` + +Maximum time, expressed in milliseconds, that can pass before the next tap — if many taps are required. The default value is 500. + +### `numberOfTaps` + +Number of tap gestures required to [activate](../basics/state.md#active) the handler. The default value is 1. + +### `maxDeltaX` + +Maximum distance, expressed in points, that defines how far the finger is allowed to travel along the X axis during a tap gesture. If the finger travels further than the defined distance along the X axis and the handler hasn't yet [activated](../basics/state.md#active), it will fail to recognize the gesture. + +### `maxDeltaY` + +Maximum distance, expressed in points, that defines how far the finger is allowed to travel along the Y axis during a tap gesture. If the finger travels further than the defined distance along the Y axis and the handler hasn't yet [activated](../basics/state.md#active), it will fail to recognize the gesture. + +### `maxDist` + +Maximum distance, expressed in points, that defines how far the finger is allowed to travel during a tap gesture. If the finger travels further than the defined distance and the handler hasn't yet [activated](../basics/state.md#active), it will fail to recognize the gesture. + +## Event data + +See [set of event attributes from base handler class](./common-gh.md#event-data). Below is a list of gesture event attributes specific to the `TapGestureHandler` component: + +### `x` + +X coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the handler. + +### `y` + +Y coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the view attached to the handler. + +### `absoluteX` + +X coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. It is recommended to use `absoluteX` instead of [`x`](#x) in cases when the view attached to the handler can be transformed as an effect of the gesture. + +### `absoluteY` + +Y coordinate, expressed in points, of the current position of the pointer (finger or a leading pointer when there are multiple fingers placed) relative to the window. It is recommended to use `absoluteY` instead of [`y`](#y) in cases when the view attached to the handler can be transformed as an effect of the gesture. + +## Example + +See the [multitap example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/basic/multitap/index.tsx) from GestureHandler Example App. + +```js +export class PressBox extends Component { + doubleTapRef = React.createRef(); + render() { + return ( + + + + + + ); + } +} +``` diff --git a/docs/versioned_docs/version-2.4.0/gesture-handlers/basics/about-handlers.md b/docs/versioned_docs/version-2.4.0/gesture-handlers/basics/about-handlers.md new file mode 100644 index 0000000000..4c2062a24f --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/gesture-handlers/basics/about-handlers.md @@ -0,0 +1,129 @@ +--- +id: about-handlers +title: About Gesture Handlers +sidebar_label: About Gesture Handlers +--- + +Gesture handlers are the core building blocks of this library. +We use this term to describe elements of the native touch system that the library allows us to instantiate and control from Javascript using [React's Component](https://reactjs.org/docs/react-component.html) interface. + +Each handler type is capable of recognizing one type of gesture (pan, pinch, etc.) and provides gesture-specific information via events (translation, scale, etc.). + +Handlers analyze touch stream synchronously in the UI thread. This allows for uninterrupted interactions even when the Javascript thread is blocked. + +Each handler works as an isolated state machine. It takes touch stream as an input and based on it, it can flip between [states](./state.md). +When a gesture starts, based on the position where the finger was placed, a set of handlers that may be interested in recognizing the gesture is selected. +All the touch events (touch down, move, up, or when other fingers are placed or lifted) are delivered to all of the handlers selected initially. +When one gesture becomes [active](./state.md#active), it cancels all the other gestures (read more about how to influence this process in ["Cross handler interactions"](./interactions.md) section). + +Gesture handler components do not instantiate a native view in the view hierarchy. Instead, they are kept in library's own registry and are only connected to native views. When using any of the gesture handler components, it is important for it to have a native view rendered as a child. +Since handler components don't have corresponding views in the hierarchy, the events registered with them are actually hooked into the underlying view. + +### Available gesture handlers + +Currently, the library provides the following list of gestures. Their parameters and attributes they provide to gesture events are documented under each gesture page: + +- [`PanGestureHandler`](../api/pan-gh.md) +- [`TapGestureHandler`](../api/tap-gh.md) +- [`LongPressGestureHandler`](../api/longpress-gh.md) +- [`RotationGestureHandler`](../api/rotation-gh.md) +- [`FlingGestureHandler`](../api/fling-gh.md) +- [`PinchGestureHandler`](../api/pinch-gh.md) +- [`ForceTouchGestureHandler`](../api/force-gh.md) + +### Discrete vs continuous + +We distinguish between two types of gestures: discrete and continuous. + +Continuous gesture handlers can be [active](./state.md#active) for a long period of time and will generate a stream of [gesture events](../api/common-gh.md#ongestureevent) until the gesture is [over](./state.md#ended). +An example of a continuous handler is [`PanGestureHandler`](../api/pan-gh.md) that once [activated](./state.md#active), will start providing updates about [translation](../api/pan-gh.md#translationx) and other properties. + +On the other hand, discrete gesture handlers once [activated](./state.md#active) will not stay in the active state but will [end](./state.md#ended) immediately. +[`LongPressGestureHandler`](../api/longpress-gh.md) is a discrete handler, as it only detects if the finger is placed for a sufficiently long period of time, it does not track finger movements (as that's the responsibility of [`PanGestureHandler`](../api/pan-gh.md)). + +Keep in mind that `onGestureEvent` is only generated in continuous gesture handlers and shouldn't be used in the `TapGestureHandler` and other discrete handlers. + +### Nesting handlers + +Handler components can be nested. In any case it is recommended that the innermost handler renders a native view component. There are some limitations that apply when [using `useNativeDriver` flag](#events-with-usenativedriver). An example of nested handlers: + +```js +class Multitap extends Component { + render() { + return ( + + + + + + + + ); + } +} +``` + +### Using native components + +Gesture handler library exposes a set of components normally available in React Native that are wrapped in [`NativeViewGestureHandler`](../api/nativeview-gh.md). +Here is a list of exposed components: + +- `ScrollView` +- `FlatList` +- `Switch` +- `TextInput` +- `DrawerLayoutAndroid` (**Android only**) + +If you want to use other handlers or [buttons](../../api/components/buttons.mdx) nested in a `ScrollView`, use the [`waitFor`](../api/common-gh.md#waitfor) property to define interaction between a handler and `ScrollView` + +### Events with `useNativeDriver` + +Because handlers do not instantiate native views but instead hook up to their child views, directly nesting two gesture handlers using `Animated.event` is not currently supported. +To workaround this limitation we recommend placing an `` component in between the handlers. + +Instead of doing: + +```js +const PanAndRotate = () => ( + + + + + +); +``` + +Place an `` in between the handlers: + +```js +const PanAndRotate = () => ( + + + + + + + +); +``` + +Another consequence of handlers depending on their native child components is that when using a `useNativeDriver` flag with an `Animated.event`, the child component must be wrapped by an `Animated.API` e.g. `` instead of just a ``: + +```js +class Draggable extends Component { + render() { + return ( + + {/* <-- NEEDS TO BE Animated.View */} + + ); + } +}; +``` diff --git a/docs/versioned_docs/version-2.4.0/gesture-handlers/basics/interactions.md b/docs/versioned_docs/version-2.4.0/gesture-handlers/basics/interactions.md new file mode 100644 index 0000000000..5b7408cf5f --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/gesture-handlers/basics/interactions.md @@ -0,0 +1,97 @@ +--- +id: interactions +title: Cross handler interactions +sidebar_label: Cross handler interactions +--- + +Gesture handlers can "communicate" with each other to support complex gestures and control how they _[activate](./state.md#active)_ in certain scenarios. + +There are two means of achieving that described in the sections below. +In each case, it is necessary to provide a reference of one handler as a property to the other. +Gesture handler relies on ref objects created using [`React.createRef()`](https://reactjs.org/docs/refs-and-the-dom.html) and introduced in [React 16.3](https://reactjs.org/blog/2018/03/29/react-v-16-3.html#createref-api). + +## Simultaneous recognition + +By default, only one gesture handler is allowed to be in the [`ACTIVE`](./state.md#active) state. +So when a gesture handler recognizes a gesture it [cancels](./state.md#cancelled) all other handlers in the [`BEGAN`](./state.md#began) state and prevents any new handlers from receiving a stream of touch events as long as it remains [`ACTIVE`](./state.md#active). + +This behavior can be altered using the [`simultaneousHandlers`](../api/common-gh.md#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.md#active) state at the same time. + +### Use cases + +Simultaneous recognition needs to be used when implementing a photo preview component that supports zooming (scaling) the photo, rotating and panning it while zoomed in. +In this case we would use a [`PinchGestureHandler`](../api/pinch-gh.md), [`RotationGestureHandler`](../api/rotation-gh.md) and [`PanGestureHandler`](../api/pan-gh.md) that would have to simultaneously recognize gestures. + +### Example + +See the ["Scale, rotate & tilt" example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/recipes/scaleAndRotate/index.tsx) from the GestureHandler Example App or view it directly on your phone by visiting [our expo demo](https://snack.expo.io/@adamgrzybowski/react-native-gesture-handler-demo). + +```js +class PinchableBox extends React.Component { + // ...take a look on full implementation in an Example app + render() { + const imagePinch = React.createRef(); + const imageRotation = React.createRef(); + return ( + + + + + + + + + + ); + } +} +``` + +## Awaiting other handlers + +### Use cases + +A good example where awaiting is necessary is when we want to have single and double tap handlers registered for one view (a button). +In such a case we need to make single tap handler await a double tap. +Otherwise if we try to perform a double tap the single tap handler will fire just after we hit the button for the first time, consequently [cancelling](./state.md#cancelled) the double tap handler. + +### Example + +See the ["Multitap" example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/basic/multitap/index.tsx) from GestureHandler Example App or view it directly on your phone by visiting [our expo demo](https://snack.expo.io/@adamgrzybowski/react-native-gesture-handler-demo). + +```js +const doubleTap = React.createRef(); +const PressBox = () => ( + + nativeEvent.state === State.ACTIVE && Alert.alert('Single tap!') + } + waitFor={doubleTap}> + + nativeEvent.state === State.ACTIVE && Alert.alert("You're so fast") + } + numberOfTaps={2}> + + + +); +``` diff --git a/docs/versioned_docs/version-2.4.0/gesture-handlers/basics/state.md b/docs/versioned_docs/version-2.4.0/gesture-handlers/basics/state.md new file mode 100644 index 0000000000..1f15f94f2f --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/gesture-handlers/basics/state.md @@ -0,0 +1,88 @@ +--- +id: state +title: Handler State +sidebar_label: Handler State +--- + +As described in ["About Gesture Handlers"](./about-handlers.md), gesture handlers can be treated as ["state machines"](https://en.wikipedia.org/wiki/Finite-state_machine). +At any given time, each handler instance has an assigned state that can change when new touch events occur or can be forced to change by the touch system in certain circumstances. + +A gesture handler can be in one of the six possible states: + +- [UNDETERMINED](#undetermined) +- [FAILED](#failed) +- [BEGAN](#began) +- [CANCELLED](#cancelled) +- [ACTIVE](#active) +- [END](#end) + +Each state has its own description below. + +## Accessing state + +We can monitor a handler's state changes by using the [`onHandlerStateChange`](../api/common-gh.md#onhandlerstatechange) callback and the destructured `nativeEvent` argument passed to it. +This can be done by comparing the `nativeEvent`'s [`state`](../api/common-gh.md#state) attribute to one of the constants exported under the `State` object (see example below). + +``` +import { State, LongPressGestureHandler } from 'react-native-gesture-handler'; + +class Demo extends Component { + _handleStateChange = ({ nativeEvent }) => { + if (nativeEvent.state === State.ACTIVE) { + Alert.alert('Longpress'); + } + }; + render() { + return ( + + Longpress me + + ); + } +} +``` + +## State flows + +The most typical flow of state is when a gesture handler picks up on an initial touch event then recognizes it then acknowledges its ending then resets itself back to the initial state. + +The flow looks as follows (longer arrows represent that there are possibly more touch events received before the state changes): + +[`UNDETERMINED`](#undetermined) -> [`BEGAN`](#began) ------> [`ACTIVE`](#active) ------> [`END`](#end) -> [`UNDETERMINED`](#undetermined) + +Another possible flow is when a handler receives touches that cause a recognition failure: + +[`UNDETERMINED`](#undetermined) -> [`BEGAN`](#began) ------> [`FAILED`](#failed) -> [`UNDETERMINED`](#undetermined) + +At last, when a handler does properly recognize the gesture but then is interrupted by the touch system. In that case, the gesture recognition is canceled and the flow looks as follows: + +[`UNDETERMINED`](#undetermined) -> [`BEGAN`](#began) ------> [`ACTIVE`](#active) ------> [`CANCELLED`](#cancelled) -> [`UNDETERMINED`](#undetermined) + +## States + +The section below describes all possible handler states: + +### UNDETERMINED + +This is the initial state of each handler and it goes into this state after it's done recognizing a gesture. + +### FAILED + +A handler received some touches but for some reason didn't recognize them. For example, if a finger travels more distance than a defined `maxDist` property allows, then the handler won't become active but will fail instead. Afterwards, it's state will be reset to `UNDETERMINED`. + +### BEGAN + +Handler has started receiving touch stream but hasn't yet received enough data to either [fail](#failed) or [activate](#active). + +### CANCELLED + +The gesture recognizer has received a signal (possibly new touches or a command from the touch system controller) resulting in the cancellation of a continuous gesture. The gesture's state will become `CANCELLED` until it is finally reset to the initial state, `UNDETERMINED`. + +### ACTIVE + +Handler has recognized a gesture. It will become and stay in the `ACTIVE` state until the gesture finishes (e.g. when user lifts the finger) or gets cancelled by the touch system. Under normal circumstances the state will then turn into `END`. In the case that a gesture is cancelled by the touch system, its state would then become `CANCELLED`. +Learn about [discrete and continuous handlers here](about-handlers#discrete-vs-continuous) to understand how long a handler can be kept in the `ACTIVE` state. + +### END + +The gesture recognizer has received touches signalling the end of a gesture. Its state will become `END` until it is reset to `UNDETERMINED`. diff --git a/docs/versioned_docs/version-2.4.0/guides/migrating-off-rnghenabledroot.md b/docs/versioned_docs/version-2.4.0/guides/migrating-off-rnghenabledroot.md new file mode 100644 index 0000000000..b72293fa64 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/guides/migrating-off-rnghenabledroot.md @@ -0,0 +1,45 @@ +--- +id: migrating-off-rnghenabledroot +title: Migrating off RNGHEnabledRootView +--- + +## Update `MainActivity.java` + +Update your `MainActivity.java` file (or wherever you create an instance of `ReactActivityDelegate`), so that it no longer overrides the method responsible for creating `ReactRootView` instance, or modify it so that it no longer uses `RNGestureHandlerEnabledRootView`. Do not forget to remove import for `RNGestureHandlerEnabledRootView`: + +```java +package com.swmansion.gesturehandler.react.example; + +import com.facebook.react.ReactActivity; +- import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView; +public class MainActivity extends ReactActivity { + +- @Override +- protected ReactActivityDelegate createReactActivityDelegate() { +- return new ReactActivityDelegate(this, getMainComponentName()) { +- @Override +- protected ReactRootView createRootView() { +- return new RNGestureHandlerEnabledRootView(MainActivity.this); +- } +- }; +- } +} +``` + +## Check if your app works correctly + +Some libraries (for example React Navigation) already use `GestureHandlerRootView` as a wrapper to enable gesture interactions. In that case you don't have to add one yourself. If gestures in your app work as expected after removing `RNGestureHandlerEnabledRootView` you can skip the next step. + +## Update your JS code + +Instead of using `RNGestureHandlerEnabledRootView` wrap your entry point with `` or `gestureHandlerRootHOC`, for example: + +```jsx +export default function App() { + return {/* content */}; +} +``` + +:::info +Note that `GestureHandlerRootView` acts like a normal `View`. So if you want it to fill the screen, you will need to pass `{ flex: 1 }` like you'll need to do with a normal View. By default, it'll take the size of the content nested inside. +::: \ No newline at end of file diff --git a/docs/versioned_docs/version-2.4.0/guides/testing.md b/docs/versioned_docs/version-2.4.0/guides/testing.md new file mode 100644 index 0000000000..980160bdbd --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/guides/testing.md @@ -0,0 +1,28 @@ +--- +id: testing +title: Testing with Jest +--- + +## Mocking native modules + +In order to load mocks provided by RNGH add following to your jest config in `package.json`: + +```json +"setupFiles": ["./node_modules/react-native-gesture-handler/jestSetup.js"] +``` + +Example: + +```json +"jest": { + "preset": "react-native", + "setupFiles": ["./node_modules/react-native-gesture-handler/jestSetup.js"] +} +``` + +## Testing Gestures' and Gesture handlers' callbacks + +RNGH provides an API for triggering selected handlers: + +- [`fireGestureHandler(gestureOrHandler, eventList)`](../api/test-api#firegesturehandlergestureorhandler-eventlist) +- [`getByGestureTestId(testID)`](../api/test-api#getbygesturetestidtestid) diff --git a/docs/versioned_docs/version-2.4.0/installation.md b/docs/versioned_docs/version-2.4.0/installation.md new file mode 100644 index 0000000000..b56ff60575 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/installation.md @@ -0,0 +1,172 @@ +--- +id: installation +title: Installation +--- + +## Requirements + +| version | `react-native` version | +| --------- | ---------------------- | +| 1.4.0+ | 0.60.0+ | +| 1.1.0+ | 0.57.2+ | +| <1.1.0 | 0.50.0+ | + +It may be possible to use newer versions of react-native-gesture-handler on React Native with version <= 0.59 by reverse Jetifying. +Read more on that here https://github.com/mikehardy/jetifier#to-reverse-jetify--convert-node_modules-dependencies-to-support-libraries + +Note that if you wish to use [`React.createRef()`](https://reactjs.org/docs/refs-and-the-dom.html) support for [interactions](./gesture-handlers/basics/interactions.md) you need to use v16.3 of [React](https://reactjs.org/) + +In order to fully utilize the [touch events](./api/gestures/touch-events.md) you also need to use `react-native-reanimated` 2.3.0-beta.4 or newer. + +## Expo + +### Managed [Expo](https://expo.io) + +To use the version of react-native-gesture-handler that is compatible with your managed Expo project, run `expo install react-native-gesture-handler`. + +The Expo SDK incorporates the latest version of react-native-gesture-handler available at the time of each SDK release, so managed Expo apps might not always support all our latest features as soon as they are available. + +### Bare [React Native](http://facebook.github.io/react-native/) + +Since the library uses native support for handling gestures, it requires an extended installation to the norm. If you are starting a new project, you may want to initialize it with [expo-cli](https://docs.expo.io/versions/latest/workflow/expo-cli/) and use a bare template, they come pre-installed with react-native-gesture-handler. + +## JS + +First, install the library using `yarn`: + +```bash +yarn add react-native-gesture-handler +``` + +or with `npm` if you prefer: + +```bash +npm install --save react-native-gesture-handler +``` + +After installation, wrap your entry point with `` or +`gestureHandlerRootHOC`. + +For example: + +```js +export default function App() { + return {/* content */}; +} +``` + +:::info +If you use props such as `shouldCancelWhenOutside`, `simultaneousHandlers`, `waitFor` etc. with gesture handlers, the handlers need to be mounted under a single `GestureHandlerRootView`. So it's important to keep the `GestureHandlerRootView` as close to the actual root view as possible. + +Note that `GestureHandlerRootView` acts like a normal `View`. So if you want it to fill the screen, you will need to pass `{ flex: 1 }` like you'll need to do with a normal `View`. By default, it'll take the size of the content nested inside. +::: + +:::tip +If you're using gesture handler in your component library, you may want to wrap your library's code in the GestureHandlerRootView component. This will avoid extra configuration for the user. +::: + +### Linking + +> **Important**: You only need to do this step if you're using React Native 0.59 or lower. Since v0.60, linking happens automatically. + +```bash +react-native link react-native-gesture-handler +``` + +## Fabric +Starting with version 2.3.0, Gesture Handler now supports [Fabric](https://reactnative.dev/docs/fabric-renderer)!. To use Gesture Handler in your Fabric application you have to: +#### on iOS: +Install pods using `RCT_NEW_ARCH_ENABLED=1 pod install` – this is the same command you run to prepare a Fabric build but you also need to run it after a new native library gets added. +#### on Android: +There are no additional steps required so long as your app is configured to build with Fabric – this is typically configured by setting `newArchEnabled=true` in `gradle.properties` file in your project. + +### With [wix/react-native-navigation](https://github.com/wix/react-native-navigation) + +If you are using a native navigation library like [wix/react-native-navigation](https://github.com/wix/react-native-navigation) you need to make sure that every screen is wrapped with `GestureHandlerRootView` (you can do this using `gestureHandlerRootHOC` function). This can be done for example at the stage when you register your screens. Here's an example: + +```js +import { gestureHandlerRootHOC } from 'react-native-gesture-handler'; +import { Navigation } from 'react-native-navigation'; +import FirstTabScreen from './FirstTabScreen'; +import SecondTabScreen from './SecondTabScreen'; +import PushedScreen from './PushedScreen'; +// register all screens of the app (including internal ones) +export function registerScreens() { + Navigation.registerComponent('example.FirstTabScreen', + () => gestureHandlerRootHOC(FirstTabScreen), + () => FirstTabScreen + ); + Navigation.registerComponent('example.SecondTabScreen', + () => gestureHandlerRootHOC(SecondTabScreen), + () => SecondTabScreen + ); + Navigation.registerComponent('example.PushedScreen', + () => gestureHandlerRootHOC(PushedScreen), + () => PushedScreen + ); +} +``` + +You can check out [this example project](https://github.com/henrikra/nativeNavigationGestureHandler) to see this kind of set up in action. + +Remember that you need to wrap each screen that you use in your app with `GestureHandlerRootView` (you can do this using `gestureHandlerRootHOC` function) as with native navigation libraries each screen maps to a separate root view. It will not be enough to wrap the main screen only. + +## Android + +### Usage with modals on Android + +On Android RNGH does not work by default because modals are not located under React Native Root view in native hierarchy. +To fix that, components need to be wrapped with `gestureHandlerRootHOC` (it's no-op on iOS and web). + +For example: + +```js +const ExampleWithHoc = gestureHandlerRootHOC(() => ( + + + + ); +); + +export default function Example() { + return ( + + + + ); +} +``` + +### Kotlin + +Since version `2.0.0` RNGH has been rewritten with Kotlin. The default version of the Kotlin plugin used in this library is `1.5.20`. + +If you need to use a different Kotlin version, set the `kotlinVersion` ext property in `android/build.gradle` file and RNGH will use that version: + +``` +buildscript { + ext { + ... + kotlinVersion = "1.5.20" + } +} +``` + +The minimal version of the Kotlin plugin supported by RNGH is `1.4.10`. + +## iOS + +There is no additional configuration required on iOS except what follows in the next steps. + +If you're in a CocoaPods project (the default setup since React Native 0.60), +make sure to install pods before you run your app: + +```bash +cd ios && pod install +``` + +For React Native 0.61 or greater, add the library as the first import in your index.js file: + +```js +import 'react-native-gesture-handler'; +``` diff --git a/docs/versioned_docs/version-2.4.0/introduction.md b/docs/versioned_docs/version-2.4.0/introduction.md new file mode 100644 index 0000000000..1ccc550cc3 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/introduction.md @@ -0,0 +1,115 @@ +--- +id: introduction +title: Introduction +sidebar_label: Introduction +slug: / +--- + +Gesture Handler aims to replace React Native's built in touch system called [Gesture Responder System](http://facebook.github.io/react-native/docs/gesture-responder-system). + +The motivation for building this library was to address the performance limitations of React Native's Gesture Responder System and to provide more control over the built-in native components that can handle gestures. +We recommend [this talk](https://www.youtube.com/watch?v=V8maYc4R2G0) by [Krzysztof Magiera](https://twitter.com/kzzzf) in which he explains issues with the responder system. + +In a nutshell, the library provides: + +- A way to use a platform's native touch handling system for recognizing pinch, rotation and pan (besides a few other gestures). +- The ability to define relations between gesture handlers, e.g. when you have a pan handler in `ScrollView` you can make that `ScrollView` wait until it knows pan won't recognize. +- Mechanisms to use touchables that run in native thread and follow platform default behavior; e.g. in the event they are in a scrollable component, turning into pressed state is slightly delayed to prevent it from highlighting when you fling. + +:::info +It is recommended to use Reanimated 2 for animations when using React Native Gesture Handler as its more advanced features rely heavily on the worklets provided by Reanimated. +::: + +## RNGH 2.0 + +RNGH2 introduces a new way of creating gestures. Instead of creating a gesture handler component for every gesture you want to create, you just need to create a `GestureDetector` component and assign to it all the gestures you want it to recognize. It is also designed to work seamlessly with `Reanimated 2` and it will automatically detect if it is installed, and start using it if it is. +You can create gestures using the `Gesture` object and methods it provides, and configure them in the builder-like pattern. If you want to specify behavior between the gestures instead of using `waitFor` and `simultaneousGestures` you can use the new system of [gesture composition](./gesture-composition). +Along the new API, version 2.0 brings one of the most requested features: [pointer events and manual gestures](./manual-gestures/manual-gestures). Thanks to great work done by the Reanimated team, we were able to provide synchronous communication between gestures and their native implementation using worklets. This allows to manage gesture state from the JS without risking race-conditions. + +### Interoperability with gesture handlers + +The new API with gestures is somewhat compatible with the old gesture handlers. Unfortunately you cannot use the new gesture composing with gesture handlers, however you can still mark relations using refs. If you want to make a gesture handler wait for (or simultaneous with) a gesture, simply use withRef method on the gesture to set the ref object and pass it to the appropriate property on the gesture handler. + +Similarly, if you want to make a gesture simultaneous with (or wait for failure of) a gesture handler, set the ref prop of the gesture handler and pass the same ref to the simultaneousWithExternalGesture or requireExternalGestureToFail method on the gesture object. + +This should allow you to migrate your codebase from the gesture handlers to gestures smoothly and at your own pace. Just keep in mind that the gesture handlers cannot have the GestureDetector as their direct child, as it's a functional component. + +## Learning resources + +### Apps + +[Gesture Handler Example App](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example) – official gesture handler "showcase" app. + +[Gesture Handler Example on Expo](https://snack.expo.io/@adamgrzybowski/react-native-gesture-handler-demo) – the official app you can install and play with using [Expo](https://expo.io). + +### Talks and workshops + +[Declarative future of gestures and animations in React Native](https://www.youtube.com/watch?v=kdq4z2708VM) by [Krzysztof Magiera](https://twitter.com/kzzzf) - talk that explains motivation behind creating gesture handler library. It also presents [react-native-reanimated](https://github.com/software-mansion/react-native-reanimated) and how and when it can be used with gesture handler. + +[React Native workshop with Expo team @ReactEurope 2018](https://youtu.be/JSIoE_ReeDk?t=41m49s) by [Brent Vetne](https://twitter.com/notbrent) – great workshop explaining gesture handler in details and presenting a few exercises that will help get you started. + +[Living in an async world of React Native](https://www.youtube.com/watch?v=-Izgons3mec) by [Krzysztof Magiera](https://twitter.com/kzzzf) – talk which highlights some issue with the React Native's touch system Gesture Handler aims to address. Also the motivation for building this library is explained. + +[React Native Touch & Gesture](https://www.youtube.com/watch?v=V8maYc4R2G0) by [Krzysztof Magiera](https://twitter.com/kzzzf) - talk explaining JS responder system limitations and points out some of the core features of Gesture Handler. + +## Contributing + +If you are interested in the project and want to contribute or support it in other ways don't hesitate to contact [me on Twitter](https://twitter.com/kzzzf)! + +All PRs are welcome, but talk to us before you start working on something big. + +The easiest way to get started with contributing code is by: + +- Reviewing the list of [open issues](https://github.com/software-mansion/react-native-gesture-handler/issues) and trying to solve the one that seem approachable to you. +- Updating the [documentation](https://github.com/software-mansion/react-native-gesture-handler/blob/main/docs) whenever you see some information is unclear, missing or out of date. + +Code is only one way how you can contribute. You may want to consider [replying on issues](https://github.com/software-mansion/react-native-gesture-handler/issues) if you know how to help. + +## Community + +We are very proud of the community that has been build around this package. We really appreciate all your help regardless of it is a pull request, issue report, helping others by commenting on existing issues or posting some demo or video tutorial on social media. +If you've build something with this library you'd like to share, please contact us as we'd love to help share it with others. + +### Gesture Handler Team 🚀 + +
+ +
+ +
Jakub Piasecki
+
+ +
+ +
Jakub Gonet
+
+ +
+ +
Krzysztof Magiera
+ @kzzzf +
+ +
+ +### Sponsors + +We really appreciate our sponsors! Thanks to them we can develop our library and make the react-native world a better place. Special thanks for: + +
+ + + + + +
diff --git a/docs/versioned_docs/version-2.4.0/manual-gestures/manual-gestures.md b/docs/versioned_docs/version-2.4.0/manual-gestures/manual-gestures.md new file mode 100644 index 0000000000..eae7fffd2d --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/manual-gestures/manual-gestures.md @@ -0,0 +1,77 @@ +--- +id: manual-gestures +title: Manual gestures +sidebar_label: Manual gestures +--- + +import Step, { Divider } from '@site/src/theme/Step'; +import Step1 from './step1.md'; +import Step2 from './step2.md'; +import Step3 from './step3.md'; +import Step4 from './step4.md'; +import Step5 from './step5.md'; +import Step6 from './step6.md'; +import Step7 from './step7.md'; + +RNGH2 finally brings one of the most requested features: manual gestures and touch events. To demonstrate how to make a manual gesture we will make a simple one that tracks all pointers on the screen. + + + + + First, we need a way to store information about the pointer: whether it should be visible and its position. + + + + + + + We also need a component to mark where a pointer is. In order to accomplish that we will make a component that accepts two shared values: one holding information about the pointer using the interface we just created, the other holding a bool indicating whether the gesture has activated. + In this example when the gesture is not active, the ball representing it will be blue and when it is active the ball will be red and slightly bigger. + + + + + + + Now we have to make a component that will handle the gesture and draw all the pointer indicators. We will store data about pointers in an array of size 12 as that is the maximum number of touches that RNGH will track, and render them inside an Animated.View. + + + + + + + We have our components set up and we can finally get to making the gesture! We will start with onTouchesDown where we need to set position of the pointers and make them visible. We can get this information from the touches property of the event. In this case we will also check how many pointers are on the screen and activate the gesture if there are at least two. + + + + + + + Next, we will handle pointer movement. In onTouchesMove we will simply update the position of moved pointers. + + + + + + + We also need to handle lifting fingers from the screen, which corresponds to onTouchesUp. Here we will just hide the pointers that were lifted and end the gesture if there are no more pointers on the screen. + Note that we are not handling onTouchesCancelled as in this very basic case we don't expect it to happen, however you should clear data about cancelled pointers (most of the time all active ones) when it is called. + + + + + + + Now that our pointers are being tracked correctly and we have the state management, we can handle activation and ending of the gesture. In our case, we will simply set the active shared value either to true or false. + + + + + +And that's all! As you can see using manual gestures is really easy but as you can imagine, manual gestures are a powerful tool that makes it possible to accomplish things that were previously impossible with RNGH. + +## Modifying existing gestures + +While manual gestures open great possibilities we are aware that reimplementing pinch or rotation from scratch just because you need to activate in specific circumstances or require position of the fingers, would be a waste of time as those gestures are already there. Because of that you can use touch events with every gesture so that you can extract more informations about gesture than is sent to you in events. We also added a `manualActivation` modifier on all continous gestures, which prevents the gesture it is applied to from activating by itself thus giving you full control of its behavior. + +This functionality makes another highly requested feature possible: drag after long press. Simply set `manualActivation` to `true` on a `PanGesture` and use `StateManager` to fail the gesture if the user attempts to drag the component sooner than the duration of the long press. diff --git a/docs/versioned_docs/version-2.4.0/manual-gestures/step1.md b/docs/versioned_docs/version-2.4.0/manual-gestures/step1.md new file mode 100644 index 0000000000..4c6331c1c8 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/manual-gestures/step1.md @@ -0,0 +1,7 @@ +```jsx +interface Pointer { + visible: boolean; + x: number; + y: number; +} +``` diff --git a/docs/versioned_docs/version-2.4.0/manual-gestures/step2.md b/docs/versioned_docs/version-2.4.0/manual-gestures/step2.md new file mode 100644 index 0000000000..3137d334ef --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/manual-gestures/step2.md @@ -0,0 +1,35 @@ +```jsx +function PointerElement(props: { + pointer: Animated.SharedValue, + active: Animated.SharedValue, +}) { + const animatedStyle = useAnimatedStyle(() => ({ + transform: [ + { translateX: props.pointer.value.x }, + { translateY: props.pointer.value.y }, + { + scale: + (props.pointer.value.visible ? 1 : 0) * + (props.active.value ? 1.3 : 1), + }, + ], + backgroundColor: props.active.value ? 'red' : 'blue', + })); + + return ; +} + +... + +const styles = StyleSheet.create({ + pointer: { + width: 60, + height: 60, + borderRadius: 30, + backgroundColor: 'red', + position: 'absolute', + marginStart: -30, + marginTop: -30, + }, +}); +``` diff --git a/docs/versioned_docs/version-2.4.0/manual-gestures/step3.md b/docs/versioned_docs/version-2.4.0/manual-gestures/step3.md new file mode 100644 index 0000000000..c9b32e5c2a --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/manual-gestures/step3.md @@ -0,0 +1,29 @@ +```jsx +export default function Example() { + const trackedPointers: Animated.SharedValue[] = []; + const active = useSharedValue(false); + + for (let i = 0; i < 12; i++) { + trackedPointers[i] = + useSharedValue < + Pointer > + { + visible: false, + x: 0, + y: 0, + }; + } + + const gesture = Gesture.Manual(); + + return ( + + + {trackedPointers.map((pointer, index) => ( + + ))} + + + ); +} +``` diff --git a/docs/versioned_docs/version-2.4.0/manual-gestures/step4.md b/docs/versioned_docs/version-2.4.0/manual-gestures/step4.md new file mode 100644 index 0000000000..36ec2c34bd --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/manual-gestures/step4.md @@ -0,0 +1,15 @@ +```jsx {2-15} +const gesture = Gesture.Manual().onTouchesDown((e, manager) => { + for (const touch of e.changedTouches) { + trackedPointers[touch.id].value = { + visible: true, + x: touch.x, + y: touch.y, + }; + } + + if (e.numberOfTouches >= 2) { + manager.activate(); + } +}); +``` diff --git a/docs/versioned_docs/version-2.4.0/manual-gestures/step5.md b/docs/versioned_docs/version-2.4.0/manual-gestures/step5.md new file mode 100644 index 0000000000..d2f9377cc8 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/manual-gestures/step5.md @@ -0,0 +1,13 @@ +```jsx {3-12} +const gesture = Gesture.Manual() + ... + .onTouchesMove((e, _manager) => { + for (const touch of e.changedTouches) { + trackedPointers[touch.id].value = { + visible: true, + x: touch.x, + y: touch.y, + }; + } + }) +``` diff --git a/docs/versioned_docs/version-2.4.0/manual-gestures/step6.md b/docs/versioned_docs/version-2.4.0/manual-gestures/step6.md new file mode 100644 index 0000000000..323f9516cb --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/manual-gestures/step6.md @@ -0,0 +1,17 @@ +```jsx {3-16} +const gesture = Gesture.Manual() + ... + .onTouchesUp((e, manager) => { + for (const touch of e.changedTouches) { + trackedPointers[touch.id].value = { + visible: false, + x: touch.x, + y: touch.y, + }; + } + + if (e.numberOfTouches === 0) { + manager.end(); + } + }) +``` diff --git a/docs/versioned_docs/version-2.4.0/manual-gestures/step7.md b/docs/versioned_docs/version-2.4.0/manual-gestures/step7.md new file mode 100644 index 0000000000..913e766ae8 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/manual-gestures/step7.md @@ -0,0 +1,10 @@ +```jsx {3-10} +const gesture = Gesture.Manual() + ... + .onStart(() => { + active.value = true; + }) + .onEnd(() => { + active.value = false; + }); +``` diff --git a/docs/versioned_docs/version-2.4.0/quickstart/quickstart.md b/docs/versioned_docs/version-2.4.0/quickstart/quickstart.md new file mode 100644 index 0000000000..c1ba3d7219 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/quickstart/quickstart.md @@ -0,0 +1,67 @@ +--- +id: quickstart +title: Quick start +sidebar_label: Quick start +--- + +import Step, { Divider } from '@site/src/theme/Step'; +import Step1 from './step1.md'; +import Step2 from './step2.md'; +import Step3 from './step3.md'; +import Step4 from './step4.md'; +import Step5 from './step5.md'; + +RNGH2 provides much simpler way to add gestures to your app. All you need to do is wrap the view that you want your gesture to work on with [`GestureDetector`](../api/gestures/gesture-detector), define the gesture and pass it to detector. That's all! + +To demonstrate how you would use the new API, let's make a simple app where you can drag a ball around. You will need to add `react-native-gesture-handler` (for gestures) and `react-native-reanimated` (for animations) modules. + + + + +
First let's define styles we will need to make the app:
+ +
+ + + + +
Then we can start writing our `Ball` component:
+ +
+ + + + +
+ We also need to define{' '} + + shared values + {' '} + to keep track of the ball position and create animated styles in order to be + able to position the ball on the screen: +
+ +
+ + + + +
And add it to the ball's styles:
+ +
+ + + + +
+ The only thing left is to define the pan gesture and assign it to the + detector: +
+ +
+ + + +Note the `start` shared value. We need it to store the position of the ball at the moment we grab it to be able to correctly position it later, because we only have access to translation relative to the starting point of the gesture. + +Now you can just add `Ball` component to some view in the app and see the results! (Or you can just check the code [here](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/new_api/reanimated/index.tsx) and see it in action in the Example app.) diff --git a/docs/versioned_docs/version-2.4.0/quickstart/step1.md b/docs/versioned_docs/version-2.4.0/quickstart/step1.md new file mode 100644 index 0000000000..1995cd907c --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/quickstart/step1.md @@ -0,0 +1,11 @@ +```jsx +const styles = StyleSheet.create({ + ball: { + width: 100, + height: 100, + borderRadius: 100, + backgroundColor: 'blue', + alignSelf: 'center', + }, +}); +``` diff --git a/docs/versioned_docs/version-2.4.0/quickstart/step2.md b/docs/versioned_docs/version-2.4.0/quickstart/step2.md new file mode 100644 index 0000000000..34c528266b --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/quickstart/step2.md @@ -0,0 +1,9 @@ +```jsx +function Ball() { + return ( + + + + ); +} +``` diff --git a/docs/versioned_docs/version-2.4.0/quickstart/step3.md b/docs/versioned_docs/version-2.4.0/quickstart/step3.md new file mode 100644 index 0000000000..ee7184ffc7 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/quickstart/step3.md @@ -0,0 +1,14 @@ +```jsx +const isPressed = useSharedValue(false); +const offset = useSharedValue({ x: 0, y: 0 }); +const animatedStyles = useAnimatedStyle(() => { + return { + transform: [ + { translateX: offset.value.x }, + { translateY: offset.value.y }, + { scale: withSpring(isPressed.value ? 1.2 : 1) }, + ], + backgroundColor: isPressed.value ? 'yellow' : 'blue', + }; +}); +``` diff --git a/docs/versioned_docs/version-2.4.0/quickstart/step4.md b/docs/versioned_docs/version-2.4.0/quickstart/step4.md new file mode 100644 index 0000000000..8e2112a3cd --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/quickstart/step4.md @@ -0,0 +1,9 @@ +```jsx {4} +... +return ( + + + +); +... +``` diff --git a/docs/versioned_docs/version-2.4.0/quickstart/step5.md b/docs/versioned_docs/version-2.4.0/quickstart/step5.md new file mode 100644 index 0000000000..c7c2e07265 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/quickstart/step5.md @@ -0,0 +1,32 @@ +```jsx +const start = useSharedValue({ x: 0, y: 0 }); +const gesture = Gesture.Pan() + .onBegin(() => { + isPressed.value = true; + }) + .onUpdate((e) => { + offset.value = { + x: e.translationX + start.value.x, + y: e.translationY + start.value.y, + }; + }) + .onEnd(() => { + start.value = { + x: offset.value.x, + y: offset.value.y, + }; + }) + .onFinalize(() => { + isPressed.value = false; + }); +``` + +```jsx {3} +... +return ( + + + +); +... +``` diff --git a/docs/versioned_docs/version-2.4.0/troubleshooting.md b/docs/versioned_docs/version-2.4.0/troubleshooting.md new file mode 100644 index 0000000000..3ce6df850c --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/troubleshooting.md @@ -0,0 +1,35 @@ +--- +id: troubleshooting +title: Troubleshooting +--- + +## Troubleshooting + +Thanks for giving this library a try! We are sorry that you might have encountered issues though. Here is how you can seek help: + +1. Search over the [issues on Github](https://github.com/software-mansion/react-native-gesture-handler/issues). There is a chance someone had this problem in the past and it has been resolved! +2. When sure your problem hasn't been reported or was reported but the proposed solution doesn't work for you please follow [our issue reporting guidelines](#reporting-issues). +3. You can try seeking help on [Expo Developers Discord](https://chat.expo.dev/) where we often hang out. +4. If you feel like reading the source code I highly recommend it, as this is by far the best resource and gives you the most up to date insights into how the library works and what might be causing the bug. +5. If you managed to find the solution consider [contributing](introduction.md#contributing) a fix or update our documentation to make this information easier to find for the others in the future. + +## Reporting issues + +This library is maintained by a very small team. +Please be mindful of that when reporting issue and when it happens that we can't get back to you as soon as you might expect. +We would love to fix all the problems as soon as possible, but often our time is constraint with other issues/features or projects. +To make it easier for us to understand your issue and to be able to approach it sooner you can help by: + +- Making sure the issue description is complete. Please include all the details about your environment (library version, RN version, device OS etc). +- It is the best to provide an example app that reproduces the issue you are having. Put it up on [gist](https://gist.github.com/), [snack](https://snack.expo.io) or create a repo on Github – it doesn't matter as long as we can easily pull it in, run and see the issue. +- Explain how you run your repro app and what steps to take to reproduce the issue. +- Isolate your issue from other dependencies you might be using and make the repro app as minimal as possible. +- If you have spent some time figuring out the root cause of the problem you can leave a note about your findings so far. +- **Do not comment on closed issues**. It is very unlikely that we are going to notice your comment in such a case. If the issue has been closed, but the proposed solution doesn't work for you, please open a new one providing all the information necessary and linking to the solution you have tried. + +## It's not a bug, it's a feature + +- Changing `enabled` prop during a gesture has no effect, only when a gesture starts (that is a finger touches the screen) the `enabled` prop is taken into consideration to decide whether to extract (or not) the gesture and provide it with stream of events to analyze. +- `Native` gesture may not conform to the standard state flow due to platform specific workarounds to incorporate native views into RNGH. +- Keep in mind that `Touchables` from RNGH are rendering two additional views that may need to be styled separately to achieve desired effect (`style` and `containerStyle` props). +- In order for the gesture composition to work, all composed gestures must be attached to the same `GestureHandlerRootView`. diff --git a/docs/versioned_docs/version-2.4.0/under-the-hood/how-does-it-work.md b/docs/versioned_docs/version-2.4.0/under-the-hood/how-does-it-work.md new file mode 100644 index 0000000000..aebed78316 --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/under-the-hood/how-does-it-work.md @@ -0,0 +1,22 @@ +--- +id: how-does-it-work +title: How does it work? +sidebar_label: How does it work? +--- + +### Units + +All handler component properties and event attributes that represent onscreen dimensions are expressed in screen density independent units we refer to as "points". +These are the units commonly used in React Native ecosystem (e.g. in the [layout system](http://facebook.github.io/react-native/docs/flexbox.html)). +They do not map directly to physical pixels but instead to [iOS's points](https://developer.apple.com/library/content/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html#//apple_ref/doc/uid/TP40010156-CH14-SW7) and to [dp](https://developer.android.com/guide/topics/resources/more-resources#Dimension) units on Android. + +## iOS + +All gestures are implemented using [UIGestureRecognizers](https://developer.apple.com/documentation/uikit/uigesturerecognizer?language=objc), some of them have been slightly modified to allow for more customization and to conform to the state flow of RNGH. When you assign a gesture configuration to the `GestureDetector`, it creates all the required recognizers and assigns them to the child view of the detector. From this point most of the heavy lifting is handled by the [UIKit](https://developer.apple.com/documentation/uikit?language=objc) (with our help to correctly implement interactions between gestures). + +## Android + +Unfortunately, Android doesn't provide an easy way of handling gestures hence most of them were implemented from scratch, including a system for managing how the gestures should interact with each other. Here's a quick overview of how it works: +When you wrap a component with `GestureHandlerRootView` it allows for the RNGH to intercept all touch events on that component and process them, deciding whether they should be handled by one of the gesture handlers or passed to the underlying view. Gesture handlers are created when you assign a gesture configuration to the `GestureDetector`, it initializes all of the necessary handlers natively. Every `GestureHandlerRootView` also has a specific handler to decide whether to pass the touch events or to consume them. It can never activate, only begin, end or be cancelled. When this handler is in the `UNDETERMINED` state it means that there is no touch in progress, however when the touch starts it transitions to the `BEGAN` state. As long as it stays in that state, no touch event is consumed, but as soon as it gets cancelled (meaning that some handler has activated) all incoming touch events get consumed, preventing underlying view from receiving them. + +When a pointer touches the screen the view tree is traversed in order to extract all handlers attached to the views below the finger (including the one attached to the `GestureHandlerRootView`) and all extracted handlers transition to the `BEGAN` state, signalling that the gesture may heve began. The touch events continue to be delivered to all extracted handlers until one of them recognizes the gesture and tries to activate. At this point the orchestrator checks whether this gesture should wait for any other of the extracted gestures to fail. If it does, it's put to the waiting list, if it doesn't, it gets activated and all other gestures (that are not simultaneous with it) get cancelled. When a gesture handlers transitions to a finished state (the gesture recognized by it stops, it fails or gets cancelled) the orchestrator check the waiting handlers. Every one of them that waited for the gesture that just failed tries to activate again (and again the orchestrator checks if it should wait for any of the extracted gestures...). diff --git a/docs/versioned_docs/version-2.4.0/under-the-hood/states-events.md b/docs/versioned_docs/version-2.4.0/under-the-hood/states-events.md new file mode 100644 index 0000000000..600f16a5cc --- /dev/null +++ b/docs/versioned_docs/version-2.4.0/under-the-hood/states-events.md @@ -0,0 +1,94 @@ +--- +id: states-events +title: Gesture states & events +sidebar_label: Gesture states & events +--- + +Every gesture can be treated as ["state machine"](https://en.wikipedia.org/wiki/Finite-state_machine). +At any given time, each handler instance has an assigned state that can change when new touch events occur or can be forced to change by the touch system in certain circumstances. + +A gesture can be in one of the six possible states: + +- #### UNDETERMINED + + This is the initial state of each gesture recognizer and it goes into this state after it's done recognizing a gesture. + +- #### FAILED + + A gesture recognizer received some touches but for some reason didn't recognize them. For example, if a finger travels more distance than a defined `maxDist` property allows, then the gesture won't become active but will fail instead. Afterwards, it's state will be reset to `UNDETERMINED`. + +- #### BEGAN + + Gesture recognizer has started receiving touch stream but hasn't yet received enough data to either [fail](#failed) or [activate](#active). + +- #### CANCELLED + + The gesture recognizer has received a signal (possibly new touches or a command from the touch system controller) resulting in the cancellation of a continuous gesture. The gesture's state will become `CANCELLED` until it is finally reset to the initial state, `UNDETERMINED`. + +- #### ACTIVE + + Recognizer has recognized a gesture. It will become and stay in the `ACTIVE` state until the gesture finishes (e.g. when user lifts the finger) or gets cancelled by the touch system. Under normal circumstances the state will then turn into `END`. In the case that a gesture is cancelled by the touch system, its state would then become `CANCELLED`. + +- #### END + + The gesture recognizer has received touches signalling the end of a gesture. Its state will become `END` until it is reset to `UNDETERMINED`. + +## State flows + +The most typical flow of state is when a gesture picks up on an initial touch event, then recognizes it, then acknowledges its ending and resets itself back to the initial state. + +The flow looks as follows (longer arrows represent that there are possibly more touch events received before the state changes): + +[`UNDETERMINED`](#undetermined) -> [`BEGAN`](#began) ------> [`ACTIVE`](#active) ------> [`END`](#end) -> [`UNDETERMINED`](#undetermined) + +Another possible flow is when a handler receives touches that cause a recognition failure: + +[`UNDETERMINED`](#undetermined) -> [`BEGAN`](#began) ------> [`FAILED`](#failed) -> [`UNDETERMINED`](#undetermined) + +At last, when a handler does properly recognize the gesture but then is interrupted by the touch system the gesture recognition is canceled and the flow looks as follows: + +[`UNDETERMINED`](#undetermined) -> [`BEGAN`](#began) ------> [`ACTIVE`](#active) ------> [`CANCELLED`](#cancelled) -> [`UNDETERMINED`](#undetermined) + +## Events + +There are three types of events in RNGH2: `StateChangeEvent`, `GestureEvent` and `PointerEvent`. The `StateChangeEvent` is send every time a gesture moves to a different state, while `GestureEvent` is send every time a gesture is updated. The first two carry a gesture-specific data and a `state` property, indicating the current state of the gesture. `StateChangeEvent` also carries a `oldState` property indicating the previous state of the gesture. `PointerEvent` carries information about raw touch events, like touching the screen or moving the finger. These events are handled internally before they are passed along to the correct callbacks: + +### `onBegin` + +Is called when a gesture transitions to the [`BEGAN`](#began) state. + +### `onStart` + +Is called when a gesture transitions to the [`ACTIVE`](#active) state. + +### `onEnd` + +Is called when a gesture transitions from the [`ACTIVE`](#active) state to the [`END`](#end), [`FAILED`](#failed), or [`CANCELLED`](#cancelled) state. If the gesture transitions to the [`END`](#end) state, the `success` argument is set to `true` otherwise it is set to `false`. + +### `onFinalize` + +Is called when a gesture transitions to the [`END`](#end), [`FAILED`](#failed), or [`CANCELLED`](#cancelled) state. If the gesture transitions to the [`END`](#end) state, the `success` argument is set to `true` otherwise it is set to `false`. If the gesture transitions from the [`ACTIVE`](#active) state, it will be called after `onEnd`. + +### `onUpdate` + +Is called every time a gesture is updated while it is in the [`ACTIVE`](#active) state. + +### `onPointerDown` + +Is called when new pointers are placed on the screen. It may carry information about more than one pointer because the events are batched. + +### `onPointerMove` + +Is called when pointers are moved on the screen. It may carry information about more than one pointer because the events are batched. + +### `onPointerUp` + +Is called when pointers are lifted from the screen. It may carry information about more than one pointer because the events are batched. + +### `onPointerCancelled` + +Is called when there will be no more information about this pointer. It may be called because the gesture has ended or was interrupted. It may carry information about more than one pointer because the events are batched. + +### `onPointerChange` + +Is called before `onPointerDown`, `onPointerMove`, `onPointerUp` and `onPointerCancelled` with the same event, which may be useful in case you share logic between them. It may carry information about more than one pointer because the events are batched. diff --git a/docs/versioned_sidebars/version-2.4.0-sidebars.json b/docs/versioned_sidebars/version-2.4.0-sidebars.json new file mode 100644 index 0000000000..8437c8e2ed --- /dev/null +++ b/docs/versioned_sidebars/version-2.4.0-sidebars.json @@ -0,0 +1,210 @@ +{ + "version-2.4.0/docs": [ + { + "type": "doc", + "id": "version-2.4.0/introduction" + }, + { + "type": "doc", + "id": "version-2.4.0/installation" + }, + { + "type": "doc", + "id": "version-2.4.0/troubleshooting" + }, + { + "collapsed": true, + "type": "category", + "label": "Guides", + "items": [ + { + "type": "doc", + "id": "version-2.4.0/quickstart/quickstart" + }, + { + "type": "doc", + "id": "version-2.4.0/gesture-composition" + }, + { + "type": "doc", + "id": "version-2.4.0/manual-gestures/manual-gestures" + }, + { + "type": "doc", + "id": "version-2.4.0/under-the-hood/states-events" + }, + { + "type": "doc", + "id": "version-2.4.0/gesture-handlers/basics/about-handlers" + }, + { + "type": "doc", + "id": "version-2.4.0/gesture-handlers/basics/interactions" + }, + { + "type": "doc", + "id": "version-2.4.0/guides/testing" + }, + { + "type": "doc", + "id": "version-2.4.0/guides/migrating-off-rnghenabledroot" + } + ] + }, + { + "collapsed": true, + "type": "category", + "label": "API reference", + "items": [ + { + "collapsed": true, + "type": "category", + "label": "Gestures", + "items": [ + { + "type": "doc", + "id": "version-2.4.0/api/gestures/gesture-detector" + }, + { + "type": "doc", + "id": "version-2.4.0/api/gestures/gesture" + }, + { + "type": "doc", + "id": "version-2.4.0/api/gestures/pan-gesture" + }, + { + "type": "doc", + "id": "version-2.4.0/api/gestures/tap-gesture" + }, + { + "type": "doc", + "id": "version-2.4.0/api/gestures/long-press-gesture" + }, + { + "type": "doc", + "id": "version-2.4.0/api/gestures/rotation-gesture" + }, + { + "type": "doc", + "id": "version-2.4.0/api/gestures/pinch-gesture" + }, + { + "type": "doc", + "id": "version-2.4.0/api/gestures/fling-gesture" + }, + { + "type": "doc", + "id": "version-2.4.0/api/gestures/force-touch-gesture" + }, + { + "type": "doc", + "id": "version-2.4.0/api/gestures/native-gesture" + }, + { + "type": "doc", + "id": "version-2.4.0/api/gestures/manual-gesture" + }, + { + "type": "doc", + "id": "version-2.4.0/api/gestures/composed-gestures" + }, + { + "type": "doc", + "id": "version-2.4.0/api/gestures/touch-events" + }, + { + "type": "doc", + "id": "version-2.4.0/api/gestures/state-manager" + } + ] + }, + { + "collapsed": true, + "type": "category", + "label": "Components", + "items": [ + { + "type": "doc", + "id": "version-2.4.0/api/components/buttons" + }, + { + "type": "doc", + "id": "version-2.4.0/api/components/swipeable" + }, + { + "type": "doc", + "id": "version-2.4.0/api/components/touchables" + }, + { + "type": "doc", + "id": "version-2.4.0/api/components/drawer-layout" + } + ] + }, + { + "collapsed": true, + "type": "category", + "label": "Gesture Handlers", + "items": [ + { + "type": "doc", + "id": "version-2.4.0/gesture-handlers/api/common-gh" + }, + { + "type": "doc", + "id": "version-2.4.0/gesture-handlers/api/pan-gh" + }, + { + "type": "doc", + "id": "version-2.4.0/gesture-handlers/api/tap-gh" + }, + { + "type": "doc", + "id": "version-2.4.0/gesture-handlers/api/longpress-gh" + }, + { + "type": "doc", + "id": "version-2.4.0/gesture-handlers/api/rotation-gh" + }, + { + "type": "doc", + "id": "version-2.4.0/gesture-handlers/api/fling-gh" + }, + { + "type": "doc", + "id": "version-2.4.0/gesture-handlers/api/pinch-gh" + }, + { + "type": "doc", + "id": "version-2.4.0/gesture-handlers/api/force-gh" + }, + { + "type": "doc", + "id": "version-2.4.0/gesture-handlers/api/nativeview-gh" + }, + { + "type": "doc", + "id": "version-2.4.0/gesture-handlers/api/create-native-wrapper" + } + ] + }, + { + "type": "doc", + "id": "version-2.4.0/api/test-api" + } + ] + }, + { + "collapsed": true, + "type": "category", + "label": "Under the hood", + "items": [ + { + "type": "doc", + "id": "version-2.4.0/under-the-hood/how-does-it-work" + } + ] + } + ] +} diff --git a/docs/versions.json b/docs/versions.json index fc36a52558..22ea8ba0a4 100644 --- a/docs/versions.json +++ b/docs/versions.json @@ -1,4 +1,5 @@ [ + "2.4.0", "2.3.0", "2.1.1", "2.0.0", diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index bf82a35c0b..a66df76a74 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -345,7 +345,7 @@ PODS: - React-perflogger (= 0.67.2) - RNCMaskedView (0.1.10): - React - - RNGestureHandler (2.3.2): + - RNGestureHandler (2.4.0): - React-Core - RNReanimated (2.3.1): - DoubleConversion @@ -584,7 +584,7 @@ SPEC CHECKSUMS: React-runtimeexecutor: 2450b43df7ffe8e805a0b3dcb2abd4282f1f1836 ReactCommon: d98c6c96b567f9b3a15f9fd4cc302c1eda8e3cf2 RNCMaskedView: 5a8ec07677aa885546a0d98da336457e2bea557f - RNGestureHandler: 6e757e487a4834e7280e98e9bac66d2d9c575e9c + RNGestureHandler: 50e6ffee79932d14ea747d4ea4cc99aac0f24e86 RNReanimated: 1326679461fa5d2399d54c18ca1432ba3e816b9e RNScreens: 2ad555d4d9fa10b91bb765ca07fe9b29d59573f0 Yoga: 9b6696970c3289e8dea34b3eda93f23e61fb8121 @@ -592,4 +592,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 25d0906e1aa3e7904eeb1a3ea9428717a9ddaa52 -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 diff --git a/ios/RNGestureHandlerButtonComponentView.mm b/ios/RNGestureHandlerButtonComponentView.mm index 57ae06c722..af99949db4 100644 --- a/ios/RNGestureHandlerButtonComponentView.mm +++ b/ios/RNGestureHandlerButtonComponentView.mm @@ -46,7 +46,7 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & { const auto &newProps = *std::static_pointer_cast(props); - _buttonView.enabled = newProps.enabled; + _buttonView.userEnabled = newProps.enabled; _buttonView.exclusiveTouch = newProps.exclusive; [super updateProps:props oldProps:oldProps]; diff --git a/package.json b/package.json index d1c9455b58..2f7e8f6f3a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-gesture-handler", - "version": "2.3.2", + "version": "2.4.0", "description": "Experimental implementation of a new declarative API for gesture handling in react-native", "scripts": { "prepare": "bob build",