From f9ca03d8f595881cb2b099aa988058f129e270cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Thu, 16 Jan 2025 14:13:51 +0100 Subject: [PATCH 1/7] remove rightOffset and updateRightElementWidth --- src/components/ReanimatedSwipeable.tsx | 36 +++++++++----------------- 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/src/components/ReanimatedSwipeable.tsx b/src/components/ReanimatedSwipeable.tsx index a480e12f38..d02eaa7244 100644 --- a/src/components/ReanimatedSwipeable.tsx +++ b/src/components/ReanimatedSwipeable.tsx @@ -21,6 +21,7 @@ import Animated, { SharedValue, interpolate, runOnJS, + runOnUI, useAnimatedStyle, useSharedValue, withSpring, @@ -256,20 +257,9 @@ const Swipeable = forwardRef( const leftWidth = useSharedValue(0); const rightWidth = useSharedValue(0); - // used for synchronizing layout measurements between JS and UI - const rightOffset = useSharedValue(null); - const showLeftProgress = useSharedValue(0); const showRightProgress = useSharedValue(0); - const updateRightElementWidth = useCallback(() => { - 'worklet'; - if (rightOffset.value === null) { - rightOffset.value = rowWidth.value; - } - rightWidth.value = Math.max(0, rowWidth.value - rightOffset.value); - }, [rightOffset, rightWidth, rowWidth]); - const updateAnimatedEvent = useCallback(() => { 'worklet'; @@ -451,8 +441,7 @@ const Swipeable = forwardRef( }, openRight() { 'worklet'; - // rightOffset and rowWidth are already much sooner than rightWidth - animateRow((rightOffset.value ?? 0) - rowWidth.value); + animateRow(-rightWidth.value); }, reset() { 'worklet'; @@ -464,8 +453,7 @@ const Swipeable = forwardRef( }), [ leftWidth, - rightOffset, - rowWidth, + rightWidth, userDrag, showLeftProgress, appliedTranslation, @@ -515,7 +503,13 @@ const Swipeable = forwardRef( )} { - rightOffset.value = nativeEvent.layout.x; + runOnUI( + () => + (rightWidth.value = Math.max( + rowWidth.value - nativeEvent.layout.x, + 0 + )) + )(); }} /> @@ -523,7 +517,8 @@ const Swipeable = forwardRef( [ appliedTranslation, renderRightActions, - rightOffset, + rightWidth, + rowWidth.value, showRightProgress, swipeableMethods, ] @@ -535,8 +530,6 @@ const Swipeable = forwardRef( const { velocityX } = event; userDrag.value = event.translationX; - updateRightElementWidth(); - const leftThresholdProp = leftThreshold ?? leftWidth.value / 2; const rightThresholdProp = rightThreshold ?? rightWidth.value / 2; @@ -574,7 +567,6 @@ const Swipeable = forwardRef( rightWidth, rowState, userDrag, - updateRightElementWidth, ] ); @@ -603,9 +595,6 @@ const Swipeable = forwardRef( .enabled(enabled !== false) .enableTrackpadTwoFingerGesture(enableTrackpadTwoFingerGesture) .activeOffsetX([-dragOffsetFromRightEdge, dragOffsetFromLeftEdge]) - .onStart(() => { - updateRightElementWidth(); - }) .onUpdate( (event: GestureUpdateEvent) => { userDrag.value = event.translationX; @@ -650,7 +639,6 @@ const Swipeable = forwardRef( onSwipeableOpenStartDrag, rowState, updateAnimatedEvent, - updateRightElementWidth, userDrag, ] ); From c89c654757779ecce0d1712713c52f093925eef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Thu, 16 Jan 2025 14:47:32 +0100 Subject: [PATCH 2/7] update left and right widths on layout change listener --- src/components/ReanimatedSwipeable.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/components/ReanimatedSwipeable.tsx b/src/components/ReanimatedSwipeable.tsx index d02eaa7244..52ed6d5810 100644 --- a/src/components/ReanimatedSwipeable.tsx +++ b/src/components/ReanimatedSwipeable.tsx @@ -8,6 +8,7 @@ import React, { useCallback, useImperativeHandle, useMemo, + useRef, } from 'react'; import { GestureObjects as Gesture } from '../handlers/gestures/gestureObjects'; import { GestureDetector } from '../handlers/gestures/GestureDetector'; @@ -462,11 +463,20 @@ const Swipeable = forwardRef( ] ); + const leftLayoutRef = useRef(null); + const rightLayoutRef = useRef(null); + const onRowLayout = useCallback( ({ nativeEvent }: LayoutChangeEvent) => { rowWidth.value = nativeEvent.layout.width; + leftLayoutRef.current?.measure((x) => + runOnUI(() => (leftWidth.value = x))() + ); + rightLayoutRef.current?.measure((x) => + runOnUI(() => (rightWidth.value = Math.max(rowWidth.value - x, 0)))() + ); }, - [rowWidth] + [leftWidth, rightWidth, rowWidth] ); const leftElement = useCallback( @@ -478,8 +488,9 @@ const Swipeable = forwardRef( swipeableMethods )} - (leftWidth.value = nativeEvent.layout.x) + runOnUI(() => (leftWidth.value = nativeEvent.layout.x))() } /> @@ -502,6 +513,7 @@ const Swipeable = forwardRef( swipeableMethods )} { runOnUI( () => From 746ac97880e37f3d2e117fe493a4922ca037fdb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Thu, 16 Jan 2025 14:49:57 +0100 Subject: [PATCH 3/7] fix .value deps inclusion --- src/components/ReanimatedSwipeable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReanimatedSwipeable.tsx b/src/components/ReanimatedSwipeable.tsx index 52ed6d5810..ea6fb8b5a3 100644 --- a/src/components/ReanimatedSwipeable.tsx +++ b/src/components/ReanimatedSwipeable.tsx @@ -530,7 +530,7 @@ const Swipeable = forwardRef( appliedTranslation, renderRightActions, rightWidth, - rowWidth.value, + rowWidth, showRightProgress, swipeableMethods, ] From f9fbace4852fef1d487d02e91fd416d3d38fea0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Fri, 17 Jan 2025 14:39:37 +0100 Subject: [PATCH 4/7] use pageX for dynamic resizing, set row width synchronyously --- src/components/ReanimatedSwipeable.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/ReanimatedSwipeable.tsx b/src/components/ReanimatedSwipeable.tsx index ea6fb8b5a3..9a8ebfe05d 100644 --- a/src/components/ReanimatedSwipeable.tsx +++ b/src/components/ReanimatedSwipeable.tsx @@ -468,12 +468,12 @@ const Swipeable = forwardRef( const onRowLayout = useCallback( ({ nativeEvent }: LayoutChangeEvent) => { - rowWidth.value = nativeEvent.layout.width; - leftLayoutRef.current?.measure((x) => - runOnUI(() => (leftWidth.value = x))() + runOnUI(() => (rowWidth.value = nativeEvent.layout.width))(); + leftLayoutRef.current?.measure((_x, _y, _w, _h, pX) => + runOnUI(() => (leftWidth.value = pX))() ); - rightLayoutRef.current?.measure((x) => - runOnUI(() => (rightWidth.value = Math.max(rowWidth.value - x, 0)))() + rightLayoutRef.current?.measure((_x, _y, _w, _h, pX) => + runOnUI(() => (rightWidth.value = rowWidth.value - pX))() ); }, [leftWidth, rightWidth, rowWidth] From fb15a34bf6540d581e02f22d4743ffd4ec857437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Fri, 17 Jan 2025 14:55:53 +0100 Subject: [PATCH 5/7] remove redundant runOnUI instances --- src/components/ReanimatedSwipeable.tsx | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/components/ReanimatedSwipeable.tsx b/src/components/ReanimatedSwipeable.tsx index 9a8ebfe05d..0179be01db 100644 --- a/src/components/ReanimatedSwipeable.tsx +++ b/src/components/ReanimatedSwipeable.tsx @@ -22,7 +22,6 @@ import Animated, { SharedValue, interpolate, runOnJS, - runOnUI, useAnimatedStyle, useSharedValue, withSpring, @@ -468,12 +467,12 @@ const Swipeable = forwardRef( const onRowLayout = useCallback( ({ nativeEvent }: LayoutChangeEvent) => { - runOnUI(() => (rowWidth.value = nativeEvent.layout.width))(); - leftLayoutRef.current?.measure((_x, _y, _w, _h, pX) => - runOnUI(() => (leftWidth.value = pX))() + rowWidth.value = nativeEvent.layout.width; + leftLayoutRef.current?.measure( + (_x, _y, _w, _h, pX) => (leftWidth.value = pX) ); - rightLayoutRef.current?.measure((_x, _y, _w, _h, pX) => - runOnUI(() => (rightWidth.value = rowWidth.value - pX))() + rightLayoutRef.current?.measure( + (_x, _y, _w, _h, pX) => (rightWidth.value = rowWidth.value - pX) ); }, [leftWidth, rightWidth, rowWidth] @@ -490,7 +489,7 @@ const Swipeable = forwardRef( - runOnUI(() => (leftWidth.value = nativeEvent.layout.x))() + (leftWidth.value = nativeEvent.layout.x) } /> @@ -515,13 +514,10 @@ const Swipeable = forwardRef( { - runOnUI( - () => - (rightWidth.value = Math.max( - rowWidth.value - nativeEvent.layout.x, - 0 - )) - )(); + rightWidth.value = Math.max( + rowWidth.value - nativeEvent.layout.x, + 0 + ); }} /> From f360ce88d41c4af3ea90c81d3e9c7c56ab231d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Fri, 17 Jan 2025 15:20:13 +0100 Subject: [PATCH 6/7] use synchronous measure to fix pre-render width bug on slow devices --- src/components/ReanimatedSwipeable.tsx | 28 +++++++++++++++----------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/components/ReanimatedSwipeable.tsx b/src/components/ReanimatedSwipeable.tsx index 0179be01db..7badc56b4b 100644 --- a/src/components/ReanimatedSwipeable.tsx +++ b/src/components/ReanimatedSwipeable.tsx @@ -8,7 +8,6 @@ import React, { useCallback, useImperativeHandle, useMemo, - useRef, } from 'react'; import { GestureObjects as Gesture } from '../handlers/gestures/gestureObjects'; import { GestureDetector } from '../handlers/gestures/GestureDetector'; @@ -21,7 +20,10 @@ import type { PanGestureHandlerEventPayload } from '../handlers/GestureHandlerEv import Animated, { SharedValue, interpolate, + measure, runOnJS, + runOnUI, + useAnimatedRef, useAnimatedStyle, useSharedValue, withSpring, @@ -462,20 +464,20 @@ const Swipeable = forwardRef( ] ); - const leftLayoutRef = useRef(null); - const rightLayoutRef = useRef(null); + const leftLayoutRef = useAnimatedRef(); + const rightLayoutRef = useAnimatedRef(); const onRowLayout = useCallback( ({ nativeEvent }: LayoutChangeEvent) => { rowWidth.value = nativeEvent.layout.width; - leftLayoutRef.current?.measure( - (_x, _y, _w, _h, pX) => (leftWidth.value = pX) - ); - rightLayoutRef.current?.measure( - (_x, _y, _w, _h, pX) => (rightWidth.value = rowWidth.value - pX) - ); + runOnUI(() => { + const leftLayout = measure(leftLayoutRef); + leftWidth.value = leftLayout?.pageX ?? 0; + const rightLayout = measure(rightLayoutRef); + rightWidth.value = rowWidth.value - (rightLayout?.pageX ?? 0); + }); }, - [leftWidth, rightWidth, rowWidth] + [leftLayoutRef, rightLayoutRef, leftWidth, rightWidth, rowWidth] ); const leftElement = useCallback( @@ -486,7 +488,7 @@ const Swipeable = forwardRef( appliedTranslation, swipeableMethods )} - (leftWidth.value = nativeEvent.layout.x) @@ -496,6 +498,7 @@ const Swipeable = forwardRef( ), [ appliedTranslation, + leftLayoutRef, leftWidth, renderLeftActions, showLeftProgress, @@ -511,7 +514,7 @@ const Swipeable = forwardRef( appliedTranslation, swipeableMethods )} - { rightWidth.value = Math.max( @@ -525,6 +528,7 @@ const Swipeable = forwardRef( [ appliedTranslation, renderRightActions, + rightLayoutRef, rightWidth, rowWidth, showRightProgress, From 22662bba6e100a698e5998b57b55b30e448a2814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacy=20=C5=81=C4=85tka?= Date: Fri, 17 Jan 2025 15:25:58 +0100 Subject: [PATCH 7/7] add explicit workletization --- src/components/ReanimatedSwipeable.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/ReanimatedSwipeable.tsx b/src/components/ReanimatedSwipeable.tsx index 7badc56b4b..72adcac989 100644 --- a/src/components/ReanimatedSwipeable.tsx +++ b/src/components/ReanimatedSwipeable.tsx @@ -471,9 +471,10 @@ const Swipeable = forwardRef( ({ nativeEvent }: LayoutChangeEvent) => { rowWidth.value = nativeEvent.layout.width; runOnUI(() => { + 'worklet'; const leftLayout = measure(leftLayoutRef); - leftWidth.value = leftLayout?.pageX ?? 0; const rightLayout = measure(rightLayoutRef); + leftWidth.value = leftLayout?.pageX ?? 0; rightWidth.value = rowWidth.value - (rightLayout?.pageX ?? 0); }); },