gpt4 book ai didi

react-native - 如何使用 react reanimated 和 react native gesture handler 来更新缩放焦点原点以进行迭代捏合手势?

转载 作者:行者123 更新时间:2023-12-02 01:41:02 24 4
gpt4 key购买 nike

我使用 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>
)

最佳答案

我们最近遇到了一个与此非常相似的事情,试图在 React Native 中制作一个 Canvas 类型的元素。我们在漫长(!)天后解决了它,所以我在下面用希望工作的代码概述了我们的思考过程。我们还支持平移和缩放,但我已经从下面的代码中删除了所有平移逻辑,因为看起来您不需要它。

我们最初做了您正在做的事情,试图在用户执行操作时跟踪每个偏移/缩放,但发现这会导致奇怪的结果,而且我们无法弄清楚如何组合变换。当用户松开手指时,物体会跳到一个新的位置,因为净焦点不正确。

我们现在跟踪用户捏合时的比例和净 x、y 值,然后在捏合结束时更容易将当前变换与之前的变换组合。

我们分别跟踪 X 和 Y 分量,但它们可以很容易地组合成一个 {x,y} 对象。

我们还确保屏幕上有 2 个手指,因为在捏合结束时,如果两个手指没有同时从屏幕上移开,焦点可能会跳到一个手指。

如果以下内容适合您,请告诉我!

import React from "react";
import { View } from "react-native";
import {
PinchGestureHandler,
} from "react-native-gesture-handler";
import Animated, {
useAnimatedStyle,
useAnimatedGestureHandler,
useSharedValue,
} from "react-native-reanimated";


export default function Canvas() {
const WIDTH = 400;
const HEIGHT = 400;

const focalX = useSharedValue(0);
const focalY = useSharedValue(0);
const xCurrent = useSharedValue(0);
const yCurrent = useSharedValue(0);
const xPrevious = useSharedValue(0);
const yPrevious = useSharedValue(0);
const scaleCurrent = useSharedValue(1);
const scalePrevious = useSharedValue(1);

const pinchHandler = useAnimatedGestureHandler({
onStart: (event) => {
if (event.numberOfPointers == 2) {
focalX.value = event.focalX;
focalY.value = event.focalY;
}
},
onActive: (event) => {
if (event.numberOfPointers == 2) {
// On Android, the onStart event gives 0,0 for the focal
// values, so we set them here instead too.
if (event.oldState === 2) {
focalX.value = event.focalX;
focalY.value = event.focalY;
}
scaleCurrent.value = event.scale;

xCurrent.value = (1 - scaleCurrent.value) * (focalX.value - WIDTH / 2);
yCurrent.value = (1 - scaleCurrent.value) * (focalY.value - HEIGHT / 2);
}
},
onEnd: () => {
scalePrevious.value = scalePrevious.value * scaleCurrent.value;

xPrevious.value = scaleCurrent.value * xPrevious.value + xCurrent.value;
yPrevious.value = scaleCurrent.value * yPrevious.value + yCurrent.value;

xCurrent.value = 0;
yCurrent.value = 0;

scaleCurrent.value = 1;
},
});

const animatedStyle = useAnimatedStyle(() => {
return {
transform: [
{ translateX: xCurrent.value },
{ translateY: yCurrent.value },
{ scale: scaleCurrent.value },
{ translateX: xPrevious.value },
{ translateY: yPrevious.value },
{ scale: scalePrevious.value },
],
};
});

return (
<View>
<PinchGestureHandler onGestureEvent={pinchHandler}>
<Animated.View style={{width: 1000, height: 1000}}>
<Animated.Image
source={{uri:<IMAGE_URI>}}
style={[{
width: WIDTH,
height: HEIGHT,
},animatedStyle]}
>
</Animated.Image>
</Animated.View>
</PinchGestureHandler>
</View>
);
}

关于react-native - 如何使用 react reanimated 和 react native gesture handler 来更新缩放焦点原点以进行迭代捏合手势?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71591464/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com