From 948783f19a6073ac0d09889bd8e3b8e68635c7ef Mon Sep 17 00:00:00 2001 From: Santiago Date: Wed, 27 Mar 2024 14:03:56 -0500 Subject: [PATCH 1/2] fix(bug)!: fix jump at the end of pinch gesture Disable pan gesture at the beginning of pinch gesture instead of the end this change has been applied to both ResumableZoom and CropZoom refs #10 --- src/commons/hooks/usePinchCommons.ts | 18 ++++++++++-------- src/components/crop/CropZoom.tsx | 1 - src/components/resumable/ResumableZoom.tsx | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/commons/hooks/usePinchCommons.ts b/src/commons/hooks/usePinchCommons.ts index c6f3bf6..063c33a 100644 --- a/src/commons/hooks/usePinchCommons.ts +++ b/src/commons/hooks/usePinchCommons.ts @@ -4,9 +4,9 @@ import { runOnJS, type SharedValue, } from 'react-native-reanimated'; -import type { - GestureUpdateEvent, - PinchGestureHandlerEventPayload, +import { + type GestureUpdateEvent, + type PinchGestureHandlerEventPayload, } from 'react-native-gesture-handler'; import { clamp } from '../utils/clamp'; @@ -69,9 +69,9 @@ export const usePinchCommons = (options: PinchOptions) => { } = options; const [gesturesEnabled, setGesturesEnabled] = useState(true); - const toggleGestures = () => { + const switchGesturesState = (value: boolean) => { if (scaleMode === ScaleMode.BOUNCE) { - setGesturesEnabled((prev) => !prev); + setGesturesEnabled(value); } }; @@ -92,12 +92,13 @@ export const usePinchCommons = (options: PinchOptions) => { translate.x.value = withTiming(toX); translate.y.value = withTiming(toY); scale.value = withTiming(toScale, undefined, () => { - runOnJS(toggleGestures)(); + runOnJS(switchGesturesState)(true); }); }; const onPinchStart = (e: PinchGestureEvent) => { 'worklet'; + runOnJS(switchGesturesState)(false); cancelAnimation(translate.x); cancelAnimation(translate.y); @@ -120,6 +121,9 @@ export const usePinchCommons = (options: PinchOptions) => { const onPinchUpdate = (e: PinchGestueUpdateEvent) => { 'worklet'; + if (e.numberOfPointers !== 2) { + return; + } let toScale = e.scale * scaleOffset.value; if (scaleMode === ScaleMode.CLAMP) { @@ -151,8 +155,6 @@ export const usePinchCommons = (options: PinchOptions) => { const onPinchEnd = (e: PinchGestureEvent) => { 'worklet'; - runOnJS(toggleGestures)(); - if (userCallbacks?.onPinchEnd) { runOnJS(userCallbacks.onPinchEnd)(e); } diff --git a/src/components/crop/CropZoom.tsx b/src/components/crop/CropZoom.tsx index 73db592..bfa89d6 100644 --- a/src/components/crop/CropZoom.tsx +++ b/src/components/crop/CropZoom.tsx @@ -164,7 +164,6 @@ const CropZoom: React.FC = (props) => { }); const pinch = Gesture.Pinch() - .enabled(gesturesEnabled) .onStart(onPinchStart) .onUpdate(onPinchUpdate) .onEnd(onPinchEnd); diff --git a/src/components/resumable/ResumableZoom.tsx b/src/components/resumable/ResumableZoom.tsx index abe3157..d90e1af 100644 --- a/src/components/resumable/ResumableZoom.tsx +++ b/src/components/resumable/ResumableZoom.tsx @@ -160,7 +160,7 @@ const ResumableZoom: React.FC = (props) => { }); const pinch = Gesture.Pinch() - .enabled(pinchEnabled && gesturesEnabled) + .enabled(pinchEnabled) .hitSlop(hitSlop) .onStart(onPinchStart) .onUpdate(onPinchUpdate) From 8422651d0818c6b7422907d5a2f375f3c92d4109 Mon Sep 17 00:00:00 2001 From: Santiago Date: Wed, 27 Mar 2024 18:56:56 -0500 Subject: [PATCH 2/2] chore(panWithPinch)!: makes panWithPinch opt in for ios users refs #10 --- src/components/crop/CropZoom.tsx | 4 ++-- src/components/resumable/ResumableZoom.tsx | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/components/crop/CropZoom.tsx b/src/components/crop/CropZoom.tsx index bfa89d6..19f9c59 100644 --- a/src/components/crop/CropZoom.tsx +++ b/src/components/crop/CropZoom.tsx @@ -1,5 +1,5 @@ import React, { useImperativeHandle } from 'react'; -import { StyleSheet, View, type ViewStyle } from 'react-native'; +import { Platform, StyleSheet, View, type ViewStyle } from 'react-native'; import Animated, { useAnimatedStyle, useDerivedValue, @@ -42,7 +42,7 @@ const CropZoom: React.FC = (props) => { maxScale: userMaxScale = -1, scaleMode = ScaleMode.BOUNCE, panMode = PanMode.FREE, - panWithPinch = true, + panWithPinch = Platform.OS !== 'ios', mode = CropMode.MANAGED, onGestureActive = undefined, OverlayComponent = undefined, diff --git a/src/components/resumable/ResumableZoom.tsx b/src/components/resumable/ResumableZoom.tsx index d90e1af..1313ec4 100644 --- a/src/components/resumable/ResumableZoom.tsx +++ b/src/components/resumable/ResumableZoom.tsx @@ -1,5 +1,10 @@ import React, { useImperativeHandle } from 'react'; -import { View, StyleSheet, type LayoutChangeEvent } from 'react-native'; +import { + Platform, + View, + StyleSheet, + type LayoutChangeEvent, +} from 'react-native'; import Animated, { useAnimatedStyle, useDerivedValue, @@ -41,7 +46,7 @@ const ResumableZoom: React.FC = (props) => { maxScale: userMaxScale = 6, panMode = PanMode.CLAMP, scaleMode = ScaleMode.BOUNCE, - panWithPinch = true, + panWithPinch = Platform.OS !== 'ios', onTap, onGestureActive, onSwipeRight,