Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,82 @@ const styles = StyleSheet.create({
`}/>


#### Views reordered during a gesture

When a re-render changes `GestureDetector`'s place in the view hierarchy (e.g., a drag-to-reorder list puts the held row at a new index), the renderer may detach the view and reattach it, which cancels the active gesture.

On Android, you can keep the gesture alive by wrapping the list in `InterceptingGestureDetector` and using `VirtualGestureDetector` for each row. The gesture is then attached through the list's detector, which stays in place.

On iOS and web the system cancels the gesture of a reattached view regardless of the detector used.

<CollapsibleCode
label="Show full example"
expandedLabel="Hide full example"
lineBounds={[11, 43]}
src={`
import React, { useState } from 'react';
import { FlatList, StyleSheet, Text, View } from 'react-native';
import {
GestureHandlerRootView,
InterceptingGestureDetector,
usePanGesture,
VirtualGestureDetector,
} from 'react-native-gesture-handler';

type RowProps = { id: string; onGrab: (id: string) => void };

function Row({ id, onGrab }: RowProps) {
const pan = usePanGesture({
runOnJS: true,
onActivate: () => onGrab(id),
});

return (
<VirtualGestureDetector gesture={pan}>
<View style={styles.row}>
<Text style={styles.text}>{id}</Text>
</View>
</VirtualGestureDetector>
);
}

export default function App() {
const [rows, setRows] = useState(['A', 'B', 'C', 'D']);

const onGrab = (id: string) =>
setRows((current) => [id, ...current.filter((row) => row !== id)]);

return (
<GestureHandlerRootView style={styles.container}>
<InterceptingGestureDetector>
<FlatList
data={rows}
keyExtractor={(id) => id}
renderItem={({ item }) => <Row id={item} onGrab={onGrab} />}
/>
</InterceptingGestureDetector>
</GestureHandlerRootView>
);
}

const styles = StyleSheet.create({
container: { flex: 1, padding: 16 },
row: {
height: 80,
marginBottom: 12,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#001A72',
},
text: {
color: 'white',
fontWeight: 'bold',
fontSize: 20,
},
});
`}/>


## Properties

### gesture
Expand Down
43 changes: 41 additions & 2 deletions packages/docs-gesture-handler/docs/guides/upgrading-to-3.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,9 @@ Full changes are as follows:
| `blocksHandlers` | `block` |


## Migrating components relying on view hierarchy
## Migrating to virtual detectors

Certain components, such as `SVG`, depend on the view hierarchy to function correctly. In Gesture Handler 3, `GestureDetector` disrupts these hierarchies. To resolve this issue, two new detectors have been introduced: [`InterceptingGestureDetector`](/docs/core-components/gesture-detectors#interceptinggesturedetector) and [`VirtualGestureDetector`](/docs/core-components/gesture-detectors#virtualgesturedetector).
In Gesture Handler 3, `GestureDetector` is a host view. This has two consequences: it disrupts components that depend on the view hierarchy, such as `SVG`, and it is detached and reattached when its place in the hierarchy changes, which cancels an active gesture. To handle both cases, two new detectors have been introduced: [`InterceptingGestureDetector`](/docs/core-components/gesture-detectors#interceptinggesturedetector) and [`VirtualGestureDetector`](/docs/core-components/gesture-detectors#virtualgesturedetector).

:::danger Detectors order
`VirtualGestureDetector` has to be a descendant of `InterceptingGestureDetector`.
Expand Down Expand Up @@ -308,6 +308,45 @@ code2={
`}
/>

### Migrating views reordered during a gesture

In Gesture Handler 2, a gesture on Android survived its view being reordered mid-gesture, for example a drag-to-reorder list putting the held row at a new index. To keep that behavior, use `InterceptingGestureDetector` and `VirtualGestureDetector`. See [Views reordered during a gesture](/docs/core-components/gesture-detectors#views-reordered-during-a-gesture) for details.

<CodeComparison
label1={"RNGH 2"}
label2={"RNGH 3"}
code1={
`
function Row() {
const pan = Gesture.Pan();

return (
<GestureDetector gesture={pan}>
<View />
</GestureDetector>
);
}

<FlatList renderItem={() => <Row />} />
`}
code2={
`
function Row() {
const pan = usePanGesture();

return (
<VirtualGestureDetector gesture={pan}>
<View />
</VirtualGestureDetector>
);
}

<InterceptingGestureDetector>
<FlatList renderItem={() => <Row />} />
</InterceptingGestureDetector>
`}
/>

## Old components

### Buttons
Expand Down
Loading