react-nativereact-native-reanimatedreact-native-gesture-handler

Reanimated clamp crashes on panguesture


I am trying to build a draggable React-native Application with reanimated and gesture handler when i tried to implement a boundary for my draggable with reanimated clamp, after I move the draggables, the app crashes.

I tried implement my own function, still crashes the app.

Here's my code

const Dragable = props => {
    const translateX = useSharedValue(props.x);
    const translateY = useSharedValue(props.y);
    const isGestureActive = useSharedValue(false);
    const pan = Gesture.Pan()
        .onStart(() => {
            isGestureActive.value = true;
        })
        .onChange((evt) => {
            translateX.value += clamp(evt.changeX,0,200);
            translateY.value +=  clamp(evt.changeY,0,200);
        })
        .onEnd(() => {
            isGestureActive.value = false;
            
        })
    const animatedStyle = useAnimatedStyle(() => {
        const zIndex = isGestureActive.value ? 1000 : 1;
        return {

            zIndex,
            transform: [
                { translateX: translateX.value },
                { translateY: translateY.value },
            ],
        };
    });

    return (
            <GestureDetector gesture={pan}>
                <Animated.View style={animatedStyle}>
                   {some child components}
                </Animated.View>
            </GestureDetector>
    );
};

Solution

  • Their clamp hook is not available on my project neither, even though I'm using 3.3.0. One solution is to use custom hooks. However, when react-native-reanimated is installed, the callbacks passed to the gestures are automatically workletized and run on the UI thread when called. Hence, using normal javaScript function would cause a crash.

    Run Gesture callback on JS

      const pan = Gesture.Pan()
        .runOnJS(true)
        .onStart(() => {
          // some logic that can call JS hooks
        })
        .onChange(() => {
          // some logic that can call JS hooks
        })
        .onEnd(() => {
          // some logic that can call JS hooks
        });
    

    Run Gesture callback on UI (-= += clampOutRange2zero())

      const clampOutRange2zero = (value, min = null, max = null) => {
        "worklet";
        const shouldClamp =
          (typeof min === "number" && value < min) ||
          (typeof max === "number" && value > max);
        return shouldClamp ? 0 : value;
      };
    
    
      const pan = Gesture.Pan()
        .onStart(() => {
          isGestureActive.value = true;
        })
        .onChange((e) => {
          translateX.value += clampOutRange2zero(e.changeX, 0, 200);
          translateY.value += clampOutRange2zero(e.changeY, 0, 200);
        })
        .onEnd(() => {
          isGestureActive.value = false;
        });
    

    Run Gesture callback on UI (= clamp())

      const clamp = (value, min = null, max = null) => {
        "worklet";
        return typeof min === "number" && value < min
          ? min
          : typeof max === "number" && value > max
          ? max
          : value;
      };
    
      const pan = Gesture.Pan()
        .onStart(() => {
          isGestureActive.value = true;
        })
        .onChange((e) => {
          translateX.value = clamp(translateX.value + e.changeX, 0, 200);
          translateY.value = clamp(translateY.value + e.changeY, 0, 200);
        })
        .onEnd(() => {
          isGestureActive.value = false;
        });