Skip to content

Commit 65c4bf5

Browse files
committed
Add Animated
1 parent af2b3bf commit 65c4bf5

6 files changed

Lines changed: 252 additions & 56 deletions

File tree

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
---
2+
id: animated-interactions
3+
title: Integration with Animated
4+
sidebar_label: Integration with Animated
5+
sidebar_position: 5
6+
---
7+
8+
import CollapsibleCode from '@site/src/components/CollapsibleCode';
9+
10+
Using hook API allows for smooth integration with the [Animated API](https://reactnative.dev/docs/animated). `Animated.event` mapping depends on `useNativeDriver` property. `Animated.event` can only be used in `onUpdate` callbacks.
11+
12+
:::danger Mixing Reanimated and Animated
13+
It is not possible to mix `Reanimated` and `Animated` in the same `GestureDetector`.
14+
:::
15+
16+
<CollapsibleCode
17+
label="Show full example"
18+
expandedLabel="Hide full example"
19+
lineBounds={[8, 31]}
20+
src={`
21+
import * as React from 'react';
22+
import { Animated, StyleSheet, useAnimatedValue } from 'react-native';
23+
import {
24+
GestureHandlerRootView,
25+
GestureDetector,
26+
usePanGesture,
27+
} from 'react-native-gesture-handler';
28+
29+
export default function App() {
30+
const value = useAnimatedValue(0);
31+
32+
const event = Animated.event(
33+
[{ nativeEvent: { handlerData: { translationX: value } } }],
34+
{
35+
useNativeDriver: true,
36+
}
37+
);
38+
39+
const gesture = usePanGesture({
40+
// highlight-next-line
41+
onUpdate: event,
42+
});
43+
44+
return (
45+
<GestureHandlerRootView>
46+
<GestureDetector gesture={gesture}>
47+
<Animated.View
48+
style={[styles.box, { transform: [{ translateX: value }] }]}
49+
/>
50+
</GestureDetector>
51+
</GestureHandlerRootView>
52+
);
53+
}
54+
55+
const styles = StyleSheet.create({
56+
box: {
57+
width: 150,
58+
height: 150,
59+
backgroundColor: '#b58df1',
60+
},
61+
});
62+
`}/>
63+
64+
## useNativeDriver
65+
66+
When using `Animated.event` with `useNativeDriver` set to `false`, it is important to set [`disableReanimated`](/docs/fundamentals/reanimated-interactions#disablereanimated) to `true` in the gesture configuration.
67+
68+
Mapping of `Animated.event` depends on the value of `useNativeDriver` property. When set to `true`, event data can be accessed through `nativeEvent.handlerData` property:
69+
70+
```jsx
71+
const value = useAnimatedValue(0);
72+
73+
const event = Animated.event(
74+
[{ nativeEvent: { handlerData: { /* translationX: value, ... */ } } }],
75+
{ useNativeDriver: true }
76+
);
77+
```
78+
79+
In case of `useNativeDriver` set to `false`, event data is accessed directly:
80+
81+
```jsx
82+
const value = useAnimatedValue(0);
83+
84+
const event = Animated.event(
85+
[ { /* translationX: value, ... */ } ],
86+
{ useNativeDriver: false }
87+
);
88+
```
89+
90+
## Usage with VirtualGestureDetector
91+
92+
Using `Animated.event` with [`VirtualGestureDetector`](/docs/fundamentals/gesture-detectors#virtualgesturedetector) is possible only when `useNativeDriver` is set to `false`.
93+
94+
<CollapsibleCode
95+
label="Show full example"
96+
expandedLabel="Hide full example"
97+
lineBounds={[8, 33]}
98+
src={`
99+
import React from 'react';
100+
import { View, StyleSheet, Animated, useAnimatedValue } from 'react-native';
101+
import {
102+
GestureHandlerRootView,
103+
InterceptingGestureDetector,
104+
usePanGesture,
105+
VirtualGestureDetector,
106+
} from 'react-native-gesture-handler';
107+
108+
export default function App() {
109+
const value = useAnimatedValue(0);
110+
const event = Animated.event([{ translationX: value }], {
111+
useNativeDriver: false,
112+
});
113+
114+
const panGesture = usePanGesture({
115+
onUpdate: event,
116+
disableReanimated: true,
117+
});
118+
119+
return (
120+
<GestureHandlerRootView style={styles.container}>
121+
<InterceptingGestureDetector>
122+
<View style={styles.outerBox}>
123+
<VirtualGestureDetector gesture={panGesture}>
124+
<Animated.View
125+
style={[styles.innerBox, { transform: [{ translateX: value }] }]}
126+
/>
127+
</VirtualGestureDetector>
128+
</View>
129+
</InterceptingGestureDetector>
130+
</GestureHandlerRootView>
131+
);
132+
}
133+
134+
const styles = StyleSheet.create({
135+
container: {
136+
flex: 1,
137+
alignItems: 'center',
138+
justifyContent: 'center',
139+
},
140+
outerBox: {
141+
backgroundColor: '#b58df1',
142+
width: 150,
143+
height: 150,
144+
},
145+
innerBox: {
146+
width: 100,
147+
height: 100,
148+
backgroundColor: 'blue',
149+
},
150+
});
151+
`}/>

packages/docs-gesture-handler/docs/fundamentals/gesture-composition.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
id: gesture-composition
33
title: Gesture composition & interactions
44
sidebar_label: Gesture composition & interactions
5-
sidebar_position: 5
5+
sidebar_position: 6
66
---
77

88
RNGH3 simplifies gesture interaction through dedicated composition hooks and configuration properties. To choose the right approach, simply ask: Are all the gestures attached to the same component?

packages/docs-gesture-handler/docs/fundamentals/gesture-detector.md

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ When using hook API, you can also integrate it directly with the [Animated API](
1515
Because `GestureDetector` supports both the hook API and the builder pattern, it is important to avoid nesting detectors that use different APIs, as this can result in unexpected behavior.
1616
:::
1717

18-
### Example
19-
20-
#### Simple example
21-
2218
```js
2319
import { GestureDetector, useTapGesture } from 'react-native-gesture-handler';
2420

@@ -41,51 +37,6 @@ export default function App() {
4137
}
4238
```
4339

44-
#### Usage with Animated API
45-
46-
```js
47-
import * as React from 'react';
48-
import { Animated, useAnimatedValue } from 'react-native';
49-
import {
50-
GestureHandlerRootView,
51-
GestureDetector,
52-
usePanGesture,
53-
} from 'react-native-gesture-handler';
54-
55-
export default function App() {
56-
const value = useAnimatedValue(0);
57-
const event = Animated.event(
58-
[{ nativeEvent: { handlerData: { translationX: value } } }],
59-
{
60-
useNativeDriver: true,
61-
}
62-
);
63-
64-
const gesture = usePanGesture({
65-
onUpdate: event,
66-
});
67-
68-
return (
69-
<GestureHandlerRootView>
70-
// highlight-next-line
71-
<GestureDetector gesture={gesture}>
72-
<Animated.View
73-
style={[
74-
{
75-
width: 150,
76-
height: 150,
77-
backgroundColor: '#b58df1',
78-
},
79-
{ transform: [{ translateX: value }] },
80-
]}
81-
/>
82-
// highlight-next-line
83-
</GestureDetector>
84-
</GestureHandlerRootView>
85-
);
86-
}
87-
```
88-
8940
## Virtual Detectors
9041

9142
In RNGH3, `GestureDetector` is a standalone host component. Depending on your view hierarchy, this can occasionally disrupt interactions between specific components. To resolve this, use `InterceptingGestureDetector` in combination with `VirtualNativeDetector`.
@@ -98,8 +49,6 @@ In RNGH3, `GestureDetector` is a standalone host component. Depending on your vi
9849

9950
`VirtualGestureDetector` is similar to the `GestureDetector` from RNGH2. Because it is not a host component, it does not interfere with the host view hierarchy. This allows you to attach gestures without disrupting functionality that depends on it.
10051

101-
### Example
102-
10352
```js
10453
import React from 'react';
10554
import { View, StyleSheet } from 'react-native';

packages/docs-gesture-handler/docs/fundamentals/reanimated-interactions.mdx

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ sidebar_position: 4
77

88
import CollapsibleCode from '@site/src/components/CollapsibleCode';
99

10-
`GestureDetector` will decide whether to use [Reanimated](https://docs.swmansion.com/react-native-reanimated/) to process provided gestures based on their configuration. If any of the callbacks is a [worklet](<(https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary/#worklet)>) and Reanimated is not explicitly turned off, tools provided by the Reanimated will be utilized bringing ability to handle gestures synchronously.
10+
`GestureDetector` will decide whether to use [Reanimated](https://docs.swmansion.com/react-native-reanimated/) to process provided gestures based on their configuration. If any of the callbacks is a [worklet](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary/#worklet) and Reanimated is not explicitly turned off, tools provided by the Reanimated will be utilized bringing ability to handle gestures synchronously.
1111

1212
## Automatic [workletization](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary/#to-workletize) of gesture callbacks
1313

@@ -115,4 +115,91 @@ export default function App() {
115115
</GestureHandlerRootView>
116116
);
117117
}
118-
`}/>
118+
`}/>
119+
120+
## Disabling Reanimated
121+
122+
Gestures created with hook API have `Reanimated` enabled by default. There are two ways of disabling it for a specific gesture.
123+
124+
### disableReanimated
125+
126+
When `disableReanimated` is set to `true` in the gesture configuration, Reanimated will be turned off for that gesture throughout the whole gesture lifecycle.
127+
128+
```jsx
129+
const gesture = usePanGesture({
130+
// highlight-next-line
131+
disableReanimated: true,
132+
133+
onUpdate: () => {
134+
console.log('Panning');
135+
},
136+
});
137+
```
138+
139+
### runOnJS
140+
141+
With `runOnJS` you can temporarily disable executing callbacks on the UI thread.
142+
143+
144+
<CollapsibleCode
145+
label="Show full example"
146+
expandedLabel="Hide full example"
147+
lineBounds={[9, 37]}
148+
src={`
149+
import React from 'react';
150+
import { View, StyleSheet, Animated } from 'react-native';
151+
import {
152+
GestureDetector,
153+
GestureHandlerRootView,
154+
usePanGesture,
155+
} from 'react-native-gesture-handler';
156+
import { useSharedValue } from 'react-native-reanimated';
157+
158+
export default function App() {
159+
// highlight-next-line
160+
const shouldRunOnJS = useSharedValue(false);
161+
162+
const panGesture = usePanGesture({
163+
onUpdate: () => {
164+
console.log(
165+
globalThis.__RUNTIME_KIND === 2
166+
? 'Running on UI thread'
167+
: 'Running on JS thread'
168+
);
169+
},
170+
onDeactivate: () => {
171+
shouldRunOnJS.value = !shouldRunOnJS.value;
172+
},
173+
// highlight-next-line
174+
runOnJS: shouldRunOnJS,
175+
});
176+
177+
return (
178+
<GestureHandlerRootView style={styles.container}>
179+
<View style={styles.outerBox}>
180+
<GestureDetector gesture={panGesture}>
181+
<Animated.View style={styles.innerBox} />
182+
</GestureDetector>
183+
</View>
184+
</GestureHandlerRootView>
185+
);
186+
}
187+
188+
const styles = StyleSheet.create({
189+
container: {
190+
flex: 1,
191+
alignItems: 'center',
192+
justifyContent: 'center',
193+
},
194+
outerBox: {
195+
backgroundColor: '#b58df1',
196+
width: 150,
197+
height: 150,
198+
},
199+
innerBox: {
200+
width: 100,
201+
height: 100,
202+
backgroundColor: 'blue',
203+
},
204+
});
205+
`}/>

packages/docs-gesture-handler/docs/fundamentals/states-events.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
id: states-events
33
title: Gesture states & events
44
sidebar_label: Gesture states & events
5-
sidebar_position: 6
5+
sidebar_position: 7
66
---
77

88
Every gesture can be treated as ["state machine"](https://en.wikipedia.org/wiki/Finite-state_machine).

packages/docs-gesture-handler/docs/gestures/_shared/base-gesture-config.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,16 @@ Default value is `true`.
7878
runOnJS: boolean | SharedValue<boolean>;
7979
```
8080

81-
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.
81+
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 switching between UI thread (when set to `false`) and JS thread (when set to `true`). **This property can be modified throughout the gesture's lifecycle**.
82+
Defaults to `false`.
83+
84+
### disableReanimated
85+
86+
```ts
87+
disableReanimated: boolean | SharedValue<boolean>;
88+
```
89+
90+
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. **This property cannot be modified throught the gesture's lifecycle**.
8291
Defaults to `false`.
8392

8493
### simultaneousWith

0 commit comments

Comments
 (0)