GNG*_*GNG 3 animation gesture react-native react-native-reanimated react-native-gesture-handler
我使用react-native-gesture-handler和react-native-reanimated构建了捏合缩放效果。用户可以在图像的任意位置捏合,以手指之间的位置为缩放原点进行放大或缩小。这很棒。我遇到的问题是允许用户以多个捏合手势放大或缩小。这需要记住用户之前的捏合手势的偏移量和缩放比例。使用我当前拥有的代码,当用户第二次捏合时,手势处理程序会记住第一次捏合手势的缩放比例值,不会正确更新缩放原点。如何在不增加转换语句数量的情况下解决此问题?
const prevZoomScale = useSharedValue(1)
const currZoomScale = useSharedValue(1)
const zoomScale = useDerivedValue(() => { return prevZoomScale.value * currZoomScale.value }, [prevZoomScale.value, currZoomScale.value])
const tempZoomScale = useSharedValue(1)
const prevOriginOffset = useSharedValue({x: 0, y: 0})
const tempOriginOffset = useSharedValue({x: 0, y: 0})
const currOriginOffset = useSharedValue({x: 0, y: 0})
const pinchOriginOffset = useDerivedValue(() =>
{
return {
x: (prevOriginOffset.value.x + currOriginOffset.value.x),
y: (prevOriginOffset.value.y + currOriginOffset.value.y)
}
},
[prevOriginOffset.value.x, prevOriginOffset.value.y, currOriginOffset.value.x, currOriginOffset.value.y]
)
const onPinchEvent = useAnimatedGestureHandler<PinchGestureHandlerGestureEvent>({
onStart: (_) => {
prevZoomScale.value = tempZoomScale.value
currZoomScale.value = 1
prevOriginOffset.value = tempOriginOffset.value
currOriginOffset.value = {x: _.focalX - SIZE / 2, y: _.focalY - SIZE / 2}
},
onActive: (event) => {
if ((event.scale * prevZoomScale.value) > 1) {
currZoomScale.value = event.scale
}
},
onEnd: (_) => {
tempZoomScale.value = zoomScale.value
tempOriginOffset.value = pinchOriginOffset.value
},
const animatedStyle = useAnimatedStyle(
() => ({
transform: [
{
translateX: (pinchOriginOffset.value.x)
},
{
translateY: (pinchOriginOffset.value.y)
},
{
scale: zoomScale.value
},
{
translateX: - (pinchOriginOffset.value.x)
},
{
translateY: - ( pinchOriginOffset.value.y)
}
],
}),
[]
)
return (
<View style={[styles.zoomScrollContainer, { backgroundColor: color.core.black }]}>
<PinchGestureHandler
onGestureEvent={onPinchEvent}
>
<Animated.View >
<Animated.Image
source={{ uri: zoomedImageUri }}
style={[styles.imageStyle, animatedStyle]}
>
</Animated.Image>
</Animated.View>
</PinchGestureHandler>
</View>
)
Run Code Online (Sandbox Code Playgroud)
我们最近遇到了与此非常相似的事情,试图在 React Native 中制作 Canvas 类型元素。我们在漫长的(!)天后解决了这个问题,所以我\xe2\x80\x99在下面概述了我们的思考过程,并给出了希望可以工作的代码。我们还支持平移和缩放,但我\xe2\x80\x99从下面的代码中删除了任何平移逻辑,因为看起来你不需要它。
\n我们最初做了你\xe2\x80\x99正在做的事情,试图跟踪用户所做的每个偏移/缩放,但发现它导致了奇怪的结果,我们无法\xe2\x80\x99解决如何结合转变。当用户松开捏合点时,对象会跳到新位置,因为净焦点不正确。
\n现在,我们在用户捏合时跟踪比例和净 x,y 值,然后在捏合结束时更容易将当前变换与先前的变换组合起来。
\n我们分别跟踪 X 和 Y 分量,但它们可以轻松组合成一个 {x,y} 对象。
\n我们还确保屏幕上有 2 个手指,因为在捏合结束时,如果两个手指没有同时从屏幕上移开,焦点可能会跳转到单个手指。
\n让我知道以下内容是否适合您!
\nimport React from "react";\nimport { View } from "react-native";\nimport {\n PinchGestureHandler,\n} from "react-native-gesture-handler";\nimport Animated, {\n useAnimatedStyle,\n useAnimatedGestureHandler,\n useSharedValue,\n} from "react-native-reanimated";\n\n\nexport default function Canvas() {\n const WIDTH = 400;\n const HEIGHT = 400;\n\n const focalX = useSharedValue(0);\n const focalY = useSharedValue(0);\n const xCurrent = useSharedValue(0);\n const yCurrent = useSharedValue(0);\n const xPrevious = useSharedValue(0);\n const yPrevious = useSharedValue(0);\n const scaleCurrent = useSharedValue(1);\n const scalePrevious = useSharedValue(1);\n\n const pinchHandler = useAnimatedGestureHandler({\n onStart: (event) => {\n if (event.numberOfPointers == 2) {\n focalX.value = event.focalX;\n focalY.value = event.focalY;\n }\n },\n onActive: (event) => {\n if (event.numberOfPointers == 2) {\n // On Android, the onStart event gives 0,0 for the focal\n // values, so we set them here instead too.\n if (event.oldState === 2) {\n focalX.value = event.focalX;\n focalY.value = event.focalY;\n }\n scaleCurrent.value = event.scale;\n\n xCurrent.value = (1 - scaleCurrent.value) * (focalX.value - WIDTH / 2);\n yCurrent.value = (1 - scaleCurrent.value) * (focalY.value - HEIGHT / 2);\n }\n },\n onEnd: () => {\n scalePrevious.value = scalePrevious.value * scaleCurrent.value;\n\n xPrevious.value = scaleCurrent.value * xPrevious.value + xCurrent.value;\n yPrevious.value = scaleCurrent.value * yPrevious.value + yCurrent.value;\n\n xCurrent.value = 0;\n yCurrent.value = 0;\n\n scaleCurrent.value = 1;\n },\n });\n\n const animatedStyle = useAnimatedStyle(() => {\n return {\n transform: [\n { translateX: xCurrent.value },\n { translateY: yCurrent.value },\n { scale: scaleCurrent.value },\n { translateX: xPrevious.value },\n { translateY: yPrevious.value },\n { scale: scalePrevious.value },\n ],\n };\n });\n\n return (\n <View>\n <PinchGestureHandler onGestureEvent={pinchHandler}>\n <Animated.View style={{width: 1000, height: 1000}}>\n <Animated.Image\n source={{uri:<IMAGE_URI>}}\n style={[{\n width: WIDTH,\n height: HEIGHT,\n },animatedStyle]}\n >\n </Animated.Image>\n </Animated.View>\n </PinchGestureHandler>\n </View>\n );\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
3060 次 |
| 最近记录: |