Revert "Zoom the finished photo with a double tap only"
This reverts commit 29b75ec3d3.
This commit is contained in:
@@ -1,21 +1,25 @@
|
||||
import React, { useRef } from 'react';
|
||||
import { Animated, PanResponder } from 'react-native';
|
||||
|
||||
// Double-tap zoom for one preview photo inside the paging strip.
|
||||
// Pinch / double-tap zoom for one preview photo inside the paging strip.
|
||||
// Core PanResponder + Animated only (no react-native-gesture-handler dep).
|
||||
// While zoomed in, responder termination is refused so the parent ScrollView
|
||||
// cannot steal the gesture — the photo pans instead of paging; swiping to the
|
||||
// next photo resumes after zooming back out (double tap).
|
||||
// next photo resumes after zooming back out (double tap or pinch below 1.15).
|
||||
// Two-finger pinch only zooms once the photo is already zoomed in: at 100% the
|
||||
// pinch stays inert, so the paging strip still behaves like a plain gallery.
|
||||
//
|
||||
// ponytail: double tap only — a finished photo is not a map, and the two-finger
|
||||
// gesture conflicted with paging. Re-add a pinch branch in onPanResponderMove
|
||||
// (scale = start * dist/startDist, clamped) if pinch is ever wanted back.
|
||||
// ponytail: pinch zooms around the image center, not the finger midpoint;
|
||||
// focal zoom needs per-touch location math against the image's screen rect.
|
||||
// MAX_SCALE is a hard cap — add a dedicated slider/stepper when 4x is not
|
||||
// enough.
|
||||
|
||||
interface ZoomableImageProps {
|
||||
uri: string;
|
||||
width: number;
|
||||
}
|
||||
|
||||
const MAX_SCALE = 4;
|
||||
const TAP_SCALE = 2.5;
|
||||
const TAP_MS = 300;
|
||||
|
||||
@@ -30,6 +34,7 @@ export default function ZoomableImage({ uri, width }: ZoomableImageProps) {
|
||||
ty: 0,
|
||||
w: width,
|
||||
h: 0,
|
||||
pinchStart: null as { scale: number; dist: number } | null,
|
||||
lastDx: 0,
|
||||
lastDy: 0,
|
||||
moved: false,
|
||||
@@ -66,7 +71,9 @@ export default function ZoomableImage({ uri, width }: ZoomableImageProps) {
|
||||
};
|
||||
|
||||
const finish = () => {
|
||||
const wasTap = !st.moved && Date.now() - st.grantAt < 400;
|
||||
const wasTap =
|
||||
!st.moved && Date.now() - st.grantAt < 400 && st.pinchStart === null;
|
||||
st.pinchStart = null;
|
||||
st.lastDx = 0;
|
||||
st.lastDy = 0;
|
||||
st.moved = false;
|
||||
@@ -92,27 +99,52 @@ export default function ZoomableImage({ uri, width }: ZoomableImageProps) {
|
||||
PanResponder.create({
|
||||
onStartShouldSetPanResponder: () => true,
|
||||
onMoveShouldSetPanResponder: () => true,
|
||||
// Page the strip while zoom is off; once zoomed the image keeps the
|
||||
// gesture so a drag pans instead of paging.
|
||||
onPanResponderTerminationRequest: () => st.scale <= 1.001,
|
||||
// Page the strip while zoom is off; once zoomed (or mid-pinch) the
|
||||
// image keeps the gesture for panning/zooming itself.
|
||||
onPanResponderTerminationRequest: () =>
|
||||
st.scale <= 1.001 && st.pinchStart === null,
|
||||
onPanResponderGrant: () => {
|
||||
st.grantAt = Date.now();
|
||||
st.moved = false;
|
||||
st.lastDx = 0;
|
||||
st.lastDy = 0;
|
||||
},
|
||||
onPanResponderMove: (_e, g) => {
|
||||
// Single finger only: pan the zoomed photo. A second finger is ignored
|
||||
// on purpose (double tap is the only way in and out of zoom).
|
||||
if (Math.abs(g.dx) > 8 || Math.abs(g.dy) > 8) st.moved = true;
|
||||
if (st.scale > 1.001) {
|
||||
st.tx += g.dx - st.lastDx;
|
||||
st.ty += g.dy - st.lastDy;
|
||||
onPanResponderMove: (e, g) => {
|
||||
const touches = e.nativeEvent.touches;
|
||||
if (touches.length >= 2) {
|
||||
const a = touches[0];
|
||||
const b = touches[1];
|
||||
const dist = Math.hypot(a.pageX - b.pageX, a.pageY - b.pageY);
|
||||
if (!st.pinchStart) st.pinchStart = { scale: st.scale, dist: dist || 1 };
|
||||
const next =
|
||||
st.pinchStart.scale > 1.001
|
||||
? Math.max(
|
||||
1,
|
||||
Math.min(MAX_SCALE, st.pinchStart.scale * (dist / st.pinchStart.dist))
|
||||
)
|
||||
: 1;
|
||||
st.scale = next;
|
||||
if (next <= 1.001) {
|
||||
st.tx = 0;
|
||||
st.ty = 0;
|
||||
}
|
||||
clampTx();
|
||||
apply();
|
||||
st.moved = true;
|
||||
st.lastDx = g.dx;
|
||||
st.lastDy = g.dy;
|
||||
} else {
|
||||
st.pinchStart = null;
|
||||
if (Math.abs(g.dx) > 8 || Math.abs(g.dy) > 8) st.moved = true;
|
||||
if (st.scale > 1.001) {
|
||||
st.tx += g.dx - st.lastDx;
|
||||
st.ty += g.dy - st.lastDy;
|
||||
clampTx();
|
||||
apply();
|
||||
}
|
||||
st.lastDx = g.dx;
|
||||
st.lastDy = g.dy;
|
||||
}
|
||||
st.lastDx = g.dx;
|
||||
st.lastDy = g.dy;
|
||||
},
|
||||
onPanResponderRelease: finish,
|
||||
onPanResponderTerminate: finish,
|
||||
|
||||
Reference in New Issue
Block a user