Skip to content

Commit

Permalink
refactor to use simultaneousWithExternalGesture
Browse files Browse the repository at this point in the history
+ updating docs with example
  • Loading branch information
MrSltun committed Jan 17, 2025
1 parent 6aea8e6 commit ee0392a
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 65 deletions.
16 changes: 14 additions & 2 deletions docs/docs/components/reanimated_swipeable.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,21 @@ style object for the container (`Animated.View`), for example to override `overf

style object for the children container (`Animated.View`), for example to apply `flex: 1`.

### `simultaneousGesture`
### `simultaneousWithExternalGesture`

An optional gesture configuration that allows another gesture to be recognized simultaneously with the swipeable gesture. This can be useful for implementing complex gesture interactions where multiple gestures need to be detected at the same time.
An optional gesture configuration that enables another gesture to be recognized simultaneously with the swipeable gesture. This is useful for allowing swipeable gestures to work simultaneously with other gestures.

For example, to enable a pan gesture alongside the swipeable gesture:

```jsx
const panGesture = Gesture.Pan();

<GestureDetector gesture={panGesture}>
<ReanimatedSwipeable simultaneousWithExternalGesture={panGesture} />
</GestureDetector>
```

More details can be found in the [gesture composition documentation](../fundamentals/gesture-composition.md#simultaneouswithexternalgesture).

### `enableTrackpadTwoFingerGesture` (iOS only)

Expand Down
130 changes: 67 additions & 63 deletions src/components/ReanimatedSwipeable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,10 @@ export interface SwipeableProps
childrenContainerStyle?: StyleProp<ViewStyle>;

/**
* A base gesture object containing the configuration and callbacks to be
* A gesture object containing the configuration and callbacks to be
* used with the swipeable's gesture handler.
*/
simultaneousGesture?: GestureType;
simultaneousWithExternalGesture?: GestureType;
}

export interface SwipeableMethods {
Expand Down Expand Up @@ -250,7 +250,7 @@ const Swipeable = forwardRef<SwipeableMethods, SwipeableProps>(
onSwipeableClose,
renderLeftActions,
renderRightActions,
simultaneousGesture,
simultaneousWithExternalGesture,
...remainingProps
} = props;

Expand Down Expand Up @@ -605,63 +605,71 @@ const Swipeable = forwardRef<SwipeableMethods, SwipeableProps>(
[close, rowState]
);

const panGesture = useMemo(
() =>
Gesture.Pan()
.enabled(enabled !== false)
.enableTrackpadTwoFingerGesture(enableTrackpadTwoFingerGesture)
.activeOffsetX([-dragOffsetFromRightEdge, dragOffsetFromLeftEdge])
.onStart(() => {
updateRightElementWidth();
})
.onUpdate(
(event: GestureUpdateEvent<PanGestureHandlerEventPayload>) => {
userDrag.value = event.translationX;

const direction =
rowState.value === -1
? SwipeDirection.RIGHT
: rowState.value === 1
? SwipeDirection.LEFT
: event.translationX > 0
? SwipeDirection.RIGHT
: SwipeDirection.LEFT;

if (!dragStarted.value) {
dragStarted.value = true;
if (rowState.value === 0 && onSwipeableOpenStartDrag) {
runOnJS(onSwipeableOpenStartDrag)(direction);
} else if (onSwipeableCloseStartDrag) {
runOnJS(onSwipeableCloseStartDrag)(direction);
}
const panGesture = useMemo(() => {
const gesture = Gesture.Pan()
.enabled(enabled !== false)
.enableTrackpadTwoFingerGesture(enableTrackpadTwoFingerGesture)
.activeOffsetX([-dragOffsetFromRightEdge, dragOffsetFromLeftEdge])
.onStart(() => {
updateRightElementWidth();
})
.onUpdate(
(event: GestureUpdateEvent<PanGestureHandlerEventPayload>) => {
userDrag.value = event.translationX;

const direction =
rowState.value === -1
? SwipeDirection.RIGHT
: rowState.value === 1
? SwipeDirection.LEFT
: event.translationX > 0
? SwipeDirection.RIGHT
: SwipeDirection.LEFT;

if (!dragStarted.value) {
dragStarted.value = true;
if (rowState.value === 0 && onSwipeableOpenStartDrag) {
runOnJS(onSwipeableOpenStartDrag)(direction);
} else if (onSwipeableCloseStartDrag) {
runOnJS(onSwipeableCloseStartDrag)(direction);
}

updateAnimatedEvent();
}
)
.onEnd(
(event: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => {
handleRelease(event);
}
)
.onFinalize(() => {
dragStarted.value = false;
}),
[
dragOffsetFromLeftEdge,
dragOffsetFromRightEdge,
dragStarted,
enableTrackpadTwoFingerGesture,
enabled,
handleRelease,
onSwipeableCloseStartDrag,
onSwipeableOpenStartDrag,
rowState,
updateAnimatedEvent,
updateRightElementWidth,
userDrag,
]
);

updateAnimatedEvent();
}
)
.onEnd(
(event: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => {
handleRelease(event);
}
)
.onFinalize(() => {
dragStarted.value = false;
});

// Add simultaneousWithExternalGesture only if it has a value
if (simultaneousWithExternalGesture) {
gesture.simultaneousWithExternalGesture(
simultaneousWithExternalGesture
);
}

return gesture;
}, [
dragOffsetFromLeftEdge,
dragOffsetFromRightEdge,
dragStarted,
enableTrackpadTwoFingerGesture,
enabled,
handleRelease,
onSwipeableCloseStartDrag,
onSwipeableOpenStartDrag,
rowState,
updateAnimatedEvent,
updateRightElementWidth,
userDrag,
simultaneousWithExternalGesture,
]);

useImperativeHandle(ref, () => swipeableMethods, [swipeableMethods]);

Expand All @@ -673,12 +681,8 @@ const Swipeable = forwardRef<SwipeableMethods, SwipeableProps>(
[appliedTranslation, rowState]
);

const swipeableGesture = simultaneousGesture
? Gesture.Simultaneous(panGesture, simultaneousGesture)
: panGesture;

const swipeableComponent = (
<GestureDetector gesture={swipeableGesture} touchAction="pan-y">
<GestureDetector gesture={panGesture} touchAction="pan-y">
<Animated.View
{...remainingProps}
onLayout={onRowLayout}
Expand Down

0 comments on commit ee0392a

Please sign in to comment.