diff --git a/packages/docs-gesture-handler/docs/gestures/use-long-press-gesture.mdx b/packages/docs-gesture-handler/docs/gestures/use-long-press-gesture.mdx
index 69c832b82f..811b2dd365 100644
--- a/packages/docs-gesture-handler/docs/gestures/use-long-press-gesture.mdx
+++ b/packages/docs-gesture-handler/docs/gestures/use-long-press-gesture.mdx
@@ -31,7 +31,7 @@ import BaseGestureCallbacks from './\_shared/base-gesture-callbacks.mdx';
import SharedValueInfo from './\_shared/shared-value-info.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](/docs/fundamentals/states-events#end) immediately after the finger is released.
+This gesture's state will 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 or if the finger is moved further than the allowable distance.
@@ -102,7 +102,7 @@ Minimum time, expressed in milliseconds, that a finger must remain pressed on th
maxDistance: number | SharedValue
;
```
-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](/docs/fundamentals/states-events#active), it will fail to recognize the gesture. The default value is 10.
+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, it will fail to recognize the gesture. The default value is 10.
### mouseButton (Web & Android only)
diff --git a/packages/docs-gesture-handler/docs/gestures/use-manual-gesture.mdx b/packages/docs-gesture-handler/docs/gestures/use-manual-gesture.mdx
index b4c5545785..edbf89b89b 100644
--- a/packages/docs-gesture-handler/docs/gestures/use-manual-gesture.mdx
+++ b/packages/docs-gesture-handler/docs/gestures/use-manual-gesture.mdx
@@ -11,32 +11,197 @@ import BaseGestureCallbacks from './\_shared/base-gesture-callbacks.mdx';
import BaseContinuousGestureCallbacks from './\_shared/base-continuous-gesture-callbacks.mdx';
import SharedValueInfo from './\_shared/shared-value-info.md';
+import Step, { Divider } from '@site/src/theme/Step';
+import Step1 from './\_manual_gesture_steps/step1.md';
+import Step2 from './\_manual_gesture_steps/step2.md';
+import Step3 from './\_manual_gesture_steps/step3.md';
+import Step4 from './\_manual_gesture_steps/step4.md';
+import Step5 from './\_manual_gesture_steps/step5.md';
+import Step6 from './\_manual_gesture_steps/step6.md';
+import Step7 from './\_manual_gesture_steps/step7.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](/docs/gestures/state-manager). It will not fail when all the pointers are lifted from the screen.
+
+A plain gesture that has no specific activation criteria nor event data set. Its state has to be controlled manually using a [state manager](/docs/fundamentals/state-manager). It will not fail when all the pointers are lifted from the screen.
+
+:::tip
+If you need to modify the activation criteria of gestures other than `Manual`, check their configuration for relevant properties or use `manualActivation` to manage their state directly.
+:::
## Example
-```jsx
+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](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary#shared-value): 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 and render them inside an [`Animated.View`](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/your-first-animation#using-an-animated-component).
+
+
+
+
+ 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`.
+
+
+
+
+Full example code
+
+```tsx
+import { StyleSheet } from 'react-native';
import {
GestureDetector,
GestureHandlerRootView,
+ GestureStateManager,
useManualGesture,
} from 'react-native-gesture-handler';
-import Animated from 'react-native-reanimated';
+import Animated, {
+ useAnimatedStyle,
+ SharedValue,
+ useSharedValue,
+} from 'react-native-reanimated';
+
+type Pointer = {
+ x: number;
+ y: number;
+ visible: boolean;
+};
+
+type PointerElementProps = {
+ pointer: SharedValue;
+ active: SharedValue;
+};
-export default function App() {
- const manualGesture = useManualGesture({});
+function PointerElement(props: PointerElementProps) {
+ 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 ;
+}
+
+export default function Example() {
+ const trackedPointers: SharedValue[] = [];
+ const active = useSharedValue(false);
+
+ for (let i = 0; i < 10; i++) {
+ trackedPointers[i] = useSharedValue({
+ x: 0,
+ y: 0,
+ visible: false,
+ });
+ }
+
+ const gesture = useManualGesture({
+ onTouchesDown: (e) => {
+ for (const touch of e.changedTouches) {
+ trackedPointers[touch.id].value = {
+ x: touch.x,
+ y: touch.y,
+ visible: true,
+ };
+ }
+
+ if (e.numberOfTouches >= 2) {
+ GestureStateManager.activate(e.handlerTag);
+ }
+ },
+ onTouchesMove: (e) => {
+ for (const touch of e.changedTouches) {
+ trackedPointers[touch.id].value = {
+ x: touch.x,
+ y: touch.y,
+ visible: true,
+ };
+ }
+ },
+ onTouchesUp: (e) => {
+ for (const touch of e.changedTouches) {
+ trackedPointers[touch.id].value = {
+ x: touch.x,
+ y: touch.y,
+ visible: false,
+ };
+ }
+
+ if (e.numberOfTouches === 0) {
+ GestureStateManager.deactivate(e.handlerTag);
+ }
+ },
+ onActivate: () => {
+ active.value = true;
+ },
+ onDeactivate: () => {
+ active.value = false;
+ },
+ });
return (
-
-
+
+
+ {trackedPointers.map((pointer, index) => (
+
+ ))}
+
);
}
+
+const styles = StyleSheet.create({
+ pointer: {
+ width: 60,
+ height: 60,
+ borderRadius: 30,
+ backgroundColor: 'red',
+ position: 'absolute',
+ marginStart: -30,
+ marginTop: -30,
+ },
+});
```
+
+
+
+## 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 available. Therefore, you can use touch events with every gesture to extract more detailed information about the gesture than what the basic events alone provide. We also added a `manualActivation` modifier on all continuous gestures, which prevents the gesture it is applied to from activating automatically, giving you full control over its behavior.
+
## Config
diff --git a/packages/docs-gesture-handler/docs/gestures/use-native-gesture.mdx b/packages/docs-gesture-handler/docs/gestures/use-native-gesture.mdx
index 509a8ae0eb..73f525c703 100644
--- a/packages/docs-gesture-handler/docs/gestures/use-native-gesture.mdx
+++ b/packages/docs-gesture-handler/docs/gestures/use-native-gesture.mdx
@@ -97,7 +97,7 @@ Do not use `Native` gesture with components exported by React Native Gesture Han
shouldActivateOnStart: boolean | SharedValue;
```
-When `true`, underlying handler will activate unconditionally when it receives any touches in [`BEGAN`](/docs/fundamentals/states-events#began) or [`UNDETERMINED`](/docs/fundamentals/states-events#undetermined) state.
+When `true`, underlying handler will activate unconditionally when it receives any touches.
### disallowInterruption
@@ -105,7 +105,7 @@ When `true`, underlying handler will activate unconditionally when it receives a
disallowInterruption: boolean | SharedValue;
```
-When `true`, cancels all other gesture handlers when changes its state to [`ACTIVE`](/docs/fundamentals/states-events#active).
+When `true`, cancels all other gesture handlers when activates.
diff --git a/packages/docs-gesture-handler/docs/gestures/use-pan-gesture.mdx b/packages/docs-gesture-handler/docs/gestures/use-pan-gesture.mdx
index d662dddd87..c58c470323 100644
--- a/packages/docs-gesture-handler/docs/gestures/use-pan-gesture.mdx
+++ b/packages/docs-gesture-handler/docs/gestures/use-pan-gesture.mdx
@@ -34,7 +34,7 @@ import SharedValueInfo from './\_shared/shared-value-info.md';
A continuous gesture that can recognize a panning (dragging) gesture and track its movement.
-The gesture [activates](/docs/fundamentals/states-events#active) when a finger is placed on the screen and moved some initial distance.
+The gesture activates 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 required for activation (allowing for multifinger swipes) may be specified.
@@ -128,7 +128,7 @@ If you wish to track the "center of mass" virtual pointer and account for its ch
minDistance: number | SharedValue;
```
-Minimum distance the finger (or multiple finger) need to travel before the gesture [activates](/docs/fundamentals/states-events#active). Expressed in points.
+Minimum distance the finger (or multiple finger) need to travel before the gesture activates. Expressed in points.
### minPointers
@@ -136,7 +136,7 @@ Minimum distance the finger (or multiple finger) need to travel before the gestu
minPointers: number | SharedValue;
```
-A number of fingers that is required to be placed before gesture can [activate](/docs/fundamentals/states-events#active). Should be a higher or equal to 0 integer.
+A number of fingers that is required to be placed before gesture can activate. Should be a higher or equal to 0 integer.
### maxPointers
@@ -144,7 +144,7 @@ A number of fingers that is required to be placed before gesture can [activate](
maxPointers: number | SharedValue;
```
-When the given number of fingers is placed on the screen and gesture hasn't yet [activated](/docs/fundamentals/states-events#active) it will fail recognizing the gesture. Should be a higher or equal to 0 integer.
+When the given number of fingers is placed on the screen and gesture hasn't yet activated it will fail recognizing the gesture. Should be a higher or equal to 0 integer.
### activateAfterLongPress
@@ -152,7 +152,7 @@ When the given number of fingers is placed on the screen and gesture hasn't yet
activateAfterLongPress: number | SharedValue;
```
-Duration in milliseconds of the `LongPress` gesture before `Pan` is allowed to [activate](/docs/fundamentals/states-events#active). If the finger is moved during that period, the gesture will [fail](/docs/fundamentals/states-events#failed). Should be a higher or equal to 0 integer. Default value is 0, meaning no `LongPress` is required to [activate](/docs/fundamentals/states-events#active) the `Pan`.
+Duration in milliseconds of the `LongPress` gesture before `Pan` is allowed to activate. If the finger is moved during that period, the gesture will fail. Should be a higher or equal to 0 integer. Default value is 0, meaning no `LongPress` is required to activate the `Pan`.
### activeOffsetX
diff --git a/packages/docs-gesture-handler/docs/gestures/use-pinch-gesture.mdx b/packages/docs-gesture-handler/docs/gestures/use-pinch-gesture.mdx
index 51fb80760a..8b730dde13 100644
--- a/packages/docs-gesture-handler/docs/gestures/use-pinch-gesture.mdx
+++ b/packages/docs-gesture-handler/docs/gestures/use-pinch-gesture.mdx
@@ -33,7 +33,7 @@ import BaseContinuousGestureCallbacks from './\_shared/base-continuous-gesture-c
import SharedValueInfo from './\_shared/shared-value-info.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](/docs/fundamentals/states-events#active) when fingers are placed on the screen and change their position.
+The gesture activates when fingers are placed on the screen and move away from each other or pull closer together.
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.
diff --git a/packages/docs-gesture-handler/docs/gestures/use-rotation-gesture.mdx b/packages/docs-gesture-handler/docs/gestures/use-rotation-gesture.mdx
index 7df09148c1..6f74aabf3c 100644
--- a/packages/docs-gesture-handler/docs/gestures/use-rotation-gesture.mdx
+++ b/packages/docs-gesture-handler/docs/gestures/use-rotation-gesture.mdx
@@ -34,7 +34,7 @@ import SharedValueInfo from './\_shared/shared-value-info.md';
A continuous gesture that can recognize a rotation gesture and track its movement.
-The gesture [activates](/docs/fundamentals/states-events#active) when fingers are placed on the screen and change position in a proper way.
+The gesture activates when fingers are placed on the screen and rotate around a common point.
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.
diff --git a/packages/docs-gesture-handler/docs/gestures/use-tap-gesture.mdx b/packages/docs-gesture-handler/docs/gestures/use-tap-gesture.mdx
index fc61c590b9..25acce6956 100644
--- a/packages/docs-gesture-handler/docs/gestures/use-tap-gesture.mdx
+++ b/packages/docs-gesture-handler/docs/gestures/use-tap-gesture.mdx
@@ -37,7 +37,7 @@ The pointers involved in these gestures must not move significantly from their i
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](/docs/fundamentals/states-events#active), specified gesture requirements such as minPointers, numberOfTaps, maxDistance, maxDuration, and maxDelay (explained below) must be met. Immediately after the gesture [activates](/docs/fundamentals/states-events#active), it will [end](/docs/fundamentals/states-events#end).
+In order for a gesture to activate, specified gesture requirements such as minPointers, numberOfTaps, maxDistance, maxDuration, and maxDelay (explained below) must be met. Immediately after the gesture activates, it will end.