react native-放大图像时,始终会缩放到中心,而不是用户手指指向的位置



我正在React native中显示一个图像。我使用的是来自react native的react-native-gesture-handler和nativeAnimated组件。

图像应该是可缩放的,放大后也可以四处移动。一切都如预期,只是它总是缩放到中心,我想不出在缩放和移动时使用焦点来实际更新X和Y的好方法。

CCD_ 3函数在每次事件更改时运行。如果我们开始缩放,我们可以从事件参数中获得焦点

const handlePinchStateChange = (event) => {
console.log(event.nativeEvent.focalX, event.nativeEvent.focalY)
}

这一切都很好,但我需要使用这些值来实时更新X和Y,而不是在事件发生后,如果我只是

translateX = event.nativeEvent.focalY

我如何才能使平移和收缩都使用焦点,以便它向用户手指所在的位置缩放和移动?

工作零食:https://snack.expo.dev/@sbv/bold芯片

工作代码:

const pinchRef = React.createRef();
const panRef = React.createRef();
const [panEnabled, setPanEnabled] = React.useState(false);
const translateX = React.useRef(new Animated.Value(0)).current;
const translateY = React.useRef(new Animated.Value(0)).current;
const scale = React.useRef(new Animated.Value(1)).current;
const onPanEvent = Animated.event(
[
{
nativeEvent: {
translationX: translateX,
translationY: translateY,
},
},
],
{
useNativeDriver: false,// cannot use nested native drivers in a snack
}
);
const onPinchEvent = Animated.event([{ nativeEvent: { scale } }], {
useNativeDriver: false, // cannot use nested native drivers in a
});
const handlePinchStateChange = (event) => {
if (event.nativeEvent.oldState === State.ACTIVE) {
setPanEnabled(true);
}
if (event.nativeEvent.scale < 1) {
Animated.spring(scale, {
toValue: 1,
useNativeDriver: true,
bounciness: 2,
}).start();
Animated.spring(translateX, {
toValue: 0,
useNativeDriver: true,
}).start();
Animated.spring(translateY, {
toValue: 0,
useNativeDriver: true,
}).start();
setPanEnabled(false);
}
};
return (
<GestureHandlerRootView>
<PanGestureHandler
ref={panRef}
onGestureEvent={onPanEvent}
enabled={panEnabled}
simultaneousHandlers={[pinchRef]}>
<PinchGestureHandler
onGestureEvent={onPinchEvent}
onHandlerStateChange={handlePinchStateChange}
simultaneousHandlers={[panRef]}
ref={pinchRef}>
<Animated.Image
source={{
uri: 'https://reactnative.dev/img/tiny_logo.png',
}}
style={{
width: '100%',
height: 300,
transform: [
{ scale },
{ perspective: 200 },
{ translateX: translateX },
{ translateY: translateY },
],
resizeMode: 'contain',
}}
/>
</PinchGestureHandler>
</PanGestureHandler>
</GestureHandlerRootView>
);

嗨,我尝试了相同的解决方案,得到了相同的结果。阅读";反应本地手势处理程序";文档和示例我制作了这个组件并运行良好。

import React, { useRef, createRef } from "react";
import { View, Animated, StyleSheet } from "react-native";
import {
PanGestureHandler,
PinchGestureHandler,
State
} from "react-native-gesture-handler";
export interface ImageWithZoomAndPanProps {
imageURI: string;
}
const ImageWithZoomAndPan = ({ imageURI }: ImageWithZoomAndPanProps) => {
const pinchRef = createRef();
const panRef = createRef();
/* Pinching */
const baseScale = useRef(new Animated.Value(1)).current;
const pinchScale = useRef(new Animated.Value(1)).current;
const scale = useRef(Animated.multiply(baseScale, pinchScale)).current;
let lastScale = 1;
const onPinchGestureEvent = Animated.event(
[
{
nativeEvent: {
scale: pinchScale
}
}
],
{ useNativeDriver: true }
);
const handlePinchStateChange = ({ nativeEvent }) => {
if (nativeEvent.oldState === State.ACTIVE) {
lastScale *= nativeEvent.scale;
baseScale.setValue(lastScale);
pinchScale.setValue(1);
}
};
/* Pan */
const translateX = useRef(new Animated.Value(0)).current;
const translateY = useRef(new Animated.Value(0)).current;
let lastOffset = { x: 0, y: 0 };
const onPanEvent = Animated.event(
[
{
nativeEvent: {
translationX: translateX,
translationY: translateY
}
}
],
{ useNativeDriver: true }
);
const handlePanStateChange = ({ nativeEvent }) => {
if (nativeEvent.oldState === State.ACTIVE) {
lastOffset.x += nativeEvent.translationX;
lastOffset.y += nativeEvent.translationY;
translateX.setOffset(lastOffset.x);
translateX.setValue(0);
translateY.setOffset(lastOffset.y);
translateY.setValue(0);
}
};
return (
<View style={styles.mainContainer}>
<PanGestureHandler
ref={panRef}
onGestureEvent={onPanEvent}
onHandlerStateChange={handlePanStateChange}
shouldCancelWhenOutside
>
<Animated.View style={[styles.wrapper]}>
<PinchGestureHandler
ref={pinchRef}
simultaneousHandlers={panRef}
onGestureEvent={onPinchGestureEvent}
onHandlerStateChange={handlePinchStateChange}
>
<Animated.View style={styles.imageContainer} collapsable={false}>
<Animated.Image
style={[
styles.pinchableImage,
{
transform: [
{ scale: scale },
{ translateX },
{ translateY }
]
}
]}
source={{ uri: imageURI }}
/>
</Animated.View>
</PinchGestureHandler>
</Animated.View>
</PanGestureHandler>
</View>
);
};
export default ImageWithZoomAndPan;

const styles = StyleSheet.create({
mainContainer: {
width: "100%",
height: "100%"
},
imageContainer: {
...StyleSheet.absoluteFillObject,
backgroundColor: "black",
overflow: "hidden",
alignItems: "center",
flex: 1,
justifyContent: "center"
},
pinchableImage: {
width: "100%",
height: "100%"
},
wrapper: {
flex: 1
}
});

最新更新