我的目标是在我的React Native应用程序中实现类似非破坏性图像裁剪的东西,其中保持长宽比。作为一个代理,我想我可以允许用户通过手势缩放和平移图像,然后保持缩放和平移值。
这一点是正确的。我遇到的一个障碍是当我试图限制平移,使图像不能平移超出其边界。我最初的想法是这样做的:
const maximumXOffset = ((scale.value - 1) / 2) * originalWidth
const maximumYOffset = ((scale.value - 1) / 2) * originalHeight
但这并没有像预期的那样工作。然后,我尝试存储原始图像大小和缩放后的图像大小,并将偏移量限制在差值的1/2,但这也不起作用-图像仍然可以平移超过其边界。
下面是该组件的大部分完整代码。我错过了什么?
// imports elided
function SingleCard({
uri,
dateString,
id,
canZoom,
}) {
const dispatch = useDispatch()
const selectTransformsForId = useMemo(makeSelectTransformsForId, [])
const transformsForId = useSelector((state) =>
selectTransformsForId(state, id)
)
const updateRedux = useCallback(
(transforms) => {
dispatch(updateTransforms({ id, transforms }))
},
[dispatch, id]
)
const zoom = useSharedValue(transformsForId.scale)
const zoomStart = useSharedValue(zoom.value)
const offset = useSharedValue({
x: transformsForId.translateX,
y: transformsForId.translateY,
})
const offsetStart = useSharedValue({ x: offset.value.x, y: offset.value.y })
const originalSize = useSharedValue({ height: 0, width: 0 })
const currentSize = useSharedValue({ height: 0, width: 0 })
const zoomStyle = useAnimatedStyle(() => ({
transform: [
{ scale: zoom.value },
{ translateX: offset.value.x },
{ translateY: offset.value.y },
],
}))
const containerRef = useAnimatedRef()
const imageRef = useAnimatedRef()
const zoomGesture = Gesture.Pinch()
.onStart(() => {
zoomStart.value = zoom.value
const measurement = measure(containerRef)
originalSize.value = {
height: measurement.height,
width: measurement.width,
}
})
.onUpdate((e) => {
zoom.value = Math.max(zoomStart.value * e.scale, 1)
const imageMeasurement = measure(imageRef)
currentSize.value = {
height: imageMeasurement.height,
width: imageMeasurement.width,
}
})
.onEnd(() => {
runOnJS(updateRedux)({ scale: zoom.value })
})
.enabled(canZoom)
.shouldCancelWhenOutside(false)
const dragGesture = Gesture.Pan()
.averageTouches(true)
.onStart(() => {
offsetStart.value = offset.value
})
.onUpdate((e) => {
const maximumXOffset =
(currentSize.value.width - originalSize.value.width) / 2
const maximumYOffset =
(currentSize.value.height - originalSize.value.height) / 2
const xOffset = Math.min(
Math.max(e.translationX + offsetStart.value.x, -maximumXOffset),
maximumXOffset
)
const yOffset = Math.min(
Math.max(e.translationY + offsetStart.value.y, -maximumYOffset),
maximumYOffset
)
offset.value = {
x: xOffset,
y: yOffset,
}
})
.onEnd(() => {
runOnJS(updateRedux)({
translateX: offset.value.x,
translateY: offset.value.y,
})
})
.minPointers(2)
.shouldCancelWhenOutside(false)
.enabled(canZoom)
const composed = Gesture.Simultaneous(dragGesture, zoomGesture)
return (
<View ref={containerRef}>
<GestureDetector gesture={composed}>
<AnimatedImage
style={[styles.image, zoomStyle]}
source={{ uri }}
ref={imageRef}
>
</GestureDetector>
</View>
)
}
const styles = StyleSheet.create({
image: {
width: '100%',
aspectRatio: 3 / 4,
position: 'relative',
}
})
export default memo(SingleCard)
1条答案
按热度按时间ttp71kqs1#
所以这里的方法很好,只是边界计算错误。工作手势代码如下所示: