React Native useAnimatedGestureHandler is not called only in onStart on web
P粉667649253
2023-08-16 15:21:08
<p><strong>Before I realized onStart() was not called</strong></p>
<p>Using PanGestureHandler on the web and trying to "drag" an AnimatedView does not work on the web. There are no obvious errors, the application builds fine and there are no warnings in the console when checking. </p>
<p>There is a warning that leads me to believe this may be the source of the problem. I get a warning on the console that reads: </p>
<p><code>"transform" style array values are deprecated. Please use a space-delimited string function, such as "scaleX(2) rotateX(15deg)". </code></p>
<p>I'm using an AnimatedView with containerStyle to transform and move objects when dragged. </p>
<p><strong>The root of the problem</strong></p>
<p>So I looked into the problem further, trying to debug it, and I realized that the onStart() callback was not being called. Since the onStart() callback is not called, the context value is never set and the context object remains empty overall. This led to my original problem, being unable to drag objects. </p>
<p>However, it will still work on iOS. For some reason on iOS the onStart() callback is called. This results in the context being populated and working fine. </p>
<p>This is my code, remember this is just a component. In the root directory, I do have a GestureHandlerRootView component wrapping the entire application.</p>
<pre class="brush:php;toolbar:false;">import { View, Image } from 'react-native';
import Animated, {
useAnimatedStyle,
useSharedValue,
useAnimatedGestureHandler,
withSpring,
} from 'react-native-reanimated';
import { PanGestureHandler, TapGestureHandler } from 'react-native-gesture-handler';
const AnimatedImage = Animated.createAnimatedComponent(Image);
const AnimatedView = Animated.createAnimatedComponent(View);
export default function EmojiSticker ({ imageSize, stickerSource }) {
const scaleImage = useSharedValue(imageSize);
const translateX = useSharedValue(0);
const translateY = useSharedValue(0);
const onDoubleTap = useAnimatedGestureHandler({
onActive: () => {
if (scaleImage.value !== imageSize * 2) {
scaleImage.value = scaleImage.value * 2;
} else {
scaleImage.value = scaleImage.value / 2;
}
},
});
const onDrag = useAnimatedGestureHandler({
onStart: (event, context) => {
context.translateX = translateX.value;
context.translateY = translateY.value;
},
onActive: (event, context) => {
translateX.value = event.translationX context.translateX;
translateY.value = event.translationY context.translateY;
},
});
const imageStyle = useAnimatedStyle(() => {
return {
width: withSpring(scaleImage.value),
height: withSpring(scaleImage.value),
};
});
const containerStyle = useAnimatedStyle(() => {
return {
transform: [
{
translateX: translateX.value,
},
{
translateY: translateY.value,
},
],
};
});
return (
<PanGestureHandler onGestureEvent={onDrag}>
<AnimatedView style={[containerStyle, { top: -350 }]}>
<TapGestureHandler onGestureEvent={onDoubleTap} numberOfTaps={2}>
<AnimatedImage
source={stickerSource}
resizeMode='contain'
style={[imageStyle, { width: imageSize, height: imageSize }]}
/>
</TapGestureHandler>
</AnimatedView>
</PanGestureHandler>
);
}</pre>
<p><strong>顺便说一下,双击手势在 Web 和 iOS 上都完美工作。</strong> 我感到困惑,因为拖动在 iOS 上完美工作,但在 Web 上却不行。The deprecation of the transform style has me trying to figure out a way to create web-specific styles, but I'm having trouble finding a situation where others have encountered this problem. I believe there is a real solution, I just may be missing it. I'm just really confused because it works perfectly on iOS but not on the web. </p>
<p>I tried to see if anyone else had a similar problem but didn't actually find anything relevant. I also tried searching on the console for the warning I saw. </p>
<p><code>"transform" style array values are deprecated. Please use a space-delimited string function, such as "scaleX(2) rotateX(15deg)". </code></p>
<p>At least when I searched for something related to React-Native, I didn't find anything related. </p>
<p>I would love to find a draggable solution on the web. </p>
I solved this problem by consulting the documentation of
react-native-reanimated
. ApparentlyuseAnimatedGestureHandler
is not deprecated as it works inonDoubleTap
, not to mentiononDrag
also works fine on iOS.But in the documentation dealing with pan gestures I found this:
So, there is no need to import
PanGestureHandler
andTapGestureHandler
from 'react-native-gesture-handler', nor from 'react-native-reanimated'useAnimatedGestureHandler
, just importGesture
andGestureDetector
from 'react-native-gesture-handler'.Gesture
replacesuseAnimatedGestureHandler
, andGestureDetector
replaces components such asPanGestureHandler
andTapGestureHandler
.I also need to create my own
contextX
andcontextY
variables usinguseSharedValue()
because as far as I know,onBegin()
andonChange()
The callback function has no context to set.Anyway, here is the fixed code, which now runs perfectly on both the web and iOS: