Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | 7x 7x 7x 7x 7x 7x 9x 9x 7x 9x 9x 9x 9x 7x 2x 2x 5x 5x 5x 5x 5x 5x 4x 4x 4x 4x 4x 4x 2x 2x 2x 2x 1x 1x 1x 4x 3x 3x 3x 3x 3x 1x 1x 7x | /**
* 相机缩放手势控制 Hook
*/
import { useCallback, useRef } from 'react';
import { PanResponder } from 'react-native';
import * as Haptics from 'expo-haptics';
interface UseZoomGestureProps {
zoom: number;
setZoom: (zoom: number) => void;
}
/**
* 相机缩放手势 Hook
* 支持双指捏合和双指垂直滑动两种方式
*/
export function useZoomGesture({ zoom, setZoom }: UseZoomGestureProps) {
const lastDistance = useRef(0);
const lastY = useRef(0);
const isZooming = useRef(false);
const zoomRef = useRef(zoom);
// 保持 zoomRef 与 zoom 同步
zoomRef.current = zoom;
// 计算两指的平均Y坐标(用于垂直滑动)
const getAverageY = useCallback((touches: any[]) => {
Iif (touches.length < 2) return 0;
return (touches[0].pageY + touches[1].pageY) / 2;
}, []);
// 计算两点之间的距离(用于捏合手势)
const getDistance = useCallback((touches: any[]) => {
Iif (touches.length < 2) return 0;
const dx = touches[0].pageX - touches[1].pageX;
const dy = touches[0].pageY - touches[1].pageY;
return Math.sqrt(dx * dx + dy * dy);
}, []);
// 创建手势响应器
const panResponder = useRef(
PanResponder.create({
onStartShouldSetPanResponder: (evt) => {
// 只在双指触摸时响应
return evt.nativeEvent.touches.length === 2;
},
onMoveShouldSetPanResponder: (evt) => {
return evt.nativeEvent.touches.length === 2;
},
onPanResponderGrant: (evt) => {
Eif (evt.nativeEvent.touches.length === 2) {
isZooming.current = true;
lastDistance.current = getDistance(evt.nativeEvent.touches);
lastY.current = getAverageY(evt.nativeEvent.touches);
console.log('🎯 双指手势开始,初始距离:', lastDistance.current, '初始Y:', lastY.current);
}
},
onPanResponderMove: (evt) => {
if (evt.nativeEvent.touches.length === 2 && isZooming.current) {
// 方式1:捏合缩放
const currentDistance = getDistance(evt.nativeEvent.touches);
const distanceDiff = currentDistance - lastDistance.current;
// 方式2:双指垂直滑动缩放
const currentY = getAverageY(evt.nativeEvent.touches);
const yDiff = lastY.current - currentY;
let zoomChange = 0;
// 捏合手势优先(降低阈值,提高灵敏度)
if (Math.abs(distanceDiff) > 3) {
zoomChange = distanceDiff / 400;
lastDistance.current = currentDistance;
console.log(
'📏 捏合缩放:',
distanceDiff.toFixed(1),
'=> zoomChange:',
zoomChange.toFixed(3)
);
}
// 如果没有明显捏合,使用垂直滑动(降低阈值)
else if (Math.abs(yDiff) > 3) {
zoomChange = yDiff / 250;
lastY.current = currentY;
console.log('↕️ 垂直滑动:', yDiff.toFixed(1), '=> zoomChange:', zoomChange.toFixed(3));
}
if (Math.abs(zoomChange) > 0.005) {
const newZoom = Math.max(0, Math.min(1, zoomRef.current + zoomChange));
setZoom(newZoom);
console.log(
'🔍 缩放更新:',
(zoomRef.current * 100).toFixed(0) + '%',
'->',
(newZoom * 100).toFixed(0) + '%'
);
// 触觉反馈(降低阈值)
Eif (Math.abs(zoomChange) > 0.03) {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
}
}
}
},
onPanResponderRelease: () => {
console.log('✋ 双指手势结束');
isZooming.current = false;
},
})
).current;
return { panResponder };
}
|