diff --git a/lib/module/views/Drawer.native.js b/lib/module/views/Drawer.native.js index 38470a658878a63919186257041098747ec55473..1836d661ca0f8fa3e886da06e72eb004cd8f585e 100644 --- a/lib/module/views/Drawer.native.js +++ b/lib/module/views/Drawer.native.js @@ -124,17 +124,33 @@ export function Drawer({ } onTransitionEnd?.(!open); }); + const animatingTo = useSharedValue(null) const toggleDrawer = React.useCallback((open, velocity) => { 'worklet'; const translateX = getDrawerTranslationX(open); + + if (translationX.value === translateX) { + return; + } + + if (animatingTo.value === (open ? 'open' : 'close')) { + return; + } + if (velocity === undefined) { runOnJS(onAnimationStart)(open); } touchStartX.value = 0; touchX.value = 0; + + // Ignore velocity that opposes the spring direction. + // Otherwise overshootClamping makes the spring snap instantly. + const isSameDirection = velocity !== undefined && (translateX > translationX.value && velocity > 0 || translateX < translationX.value && velocity < 0); + const effectiveVelocity = isSameDirection ? velocity : 0; + animatingTo.value = open ? 'open' : 'close'; translationX.value = withSpring(translateX, { - velocity, + velocity: effectiveVelocity, stiffness: 1000, damping: 500, mass: 3, @@ -142,14 +158,19 @@ export function Drawer({ restDisplacementThreshold: 0.01, restSpeedThreshold: 0.01, reduceMotion: ReduceMotion.Never - }, finished => runOnJS(onAnimationEnd)(open, finished)); + }, finished => { + animatingTo.value = null; + runOnJS(onAnimationEnd)(open, finished); + }); if (open) { runOnJS(onOpen)(); } else { runOnJS(onClose)(); } }, [getDrawerTranslationX, onAnimationEnd, onAnimationStart, onClose, onOpen, touchStartX, touchX, translationX]); - React.useEffect(() => toggleDrawer(open), [open, toggleDrawer]); + React.useLayoutEffect(() => { + toggleDrawer(open); + }, [open, toggleDrawer]); const startX = useSharedValue(0); const pan = React.useMemo(() => { let panGesture = Gesture?.Pan().onBegin(event => {