react-native-gesture-image-viewer 2.1.2 → 2.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/module/GestureTrigger.js.map +1 -1
- package/lib/module/GestureViewer.js +37 -30
- package/lib/module/GestureViewer.js.map +1 -1
- package/lib/module/GestureViewerManager.js.map +1 -1
- package/lib/module/GestureViewerRegistry.js.map +1 -1
- package/lib/module/WebPagingFixStyle.js.map +1 -1
- package/lib/module/useGestureViewer.js +168 -173
- package/lib/module/useGestureViewer.js.map +1 -1
- package/lib/module/useGestureViewerController.js.map +1 -1
- package/lib/module/useGestureViewerEvent.js.map +1 -1
- package/lib/module/useGestureViewerState.js.map +1 -1
- package/lib/module/utils/index.js +14 -16
- package/lib/module/utils/index.js.map +1 -1
- package/lib/typescript/src/GestureTrigger.d.ts +1 -1
- package/lib/typescript/src/GestureTrigger.d.ts.map +1 -1
- package/lib/typescript/src/GestureViewer.d.ts.map +1 -1
- package/lib/typescript/src/GestureViewerManager.d.ts.map +1 -1
- package/lib/typescript/src/GestureViewerRegistry.d.ts.map +1 -1
- package/lib/typescript/src/WebPagingFixStyle.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useGestureViewer.d.ts +11 -10
- package/lib/typescript/src/useGestureViewer.d.ts.map +1 -1
- package/lib/typescript/src/useGestureViewerController.d.ts.map +1 -1
- package/lib/typescript/src/useGestureViewerEvent.d.ts.map +1 -1
- package/lib/typescript/src/useGestureViewerState.d.ts.map +1 -1
- package/lib/typescript/src/utils/index.d.ts +1 -1
- package/lib/typescript/src/utils/index.d.ts.map +1 -1
- package/package.json +86 -80
- package/src/GestureTrigger.tsx +9 -2
- package/src/GestureViewer.tsx +46 -21
- package/src/GestureViewerManager.ts +33 -6
- package/src/GestureViewerRegistry.ts +1 -0
- package/src/WebPagingFixStyle.tsx +1 -0
- package/src/types.ts +44 -32
- package/src/useGestureViewer.ts +267 -220
- package/src/useGestureViewerController.ts +1 -0
- package/src/useGestureViewerEvent.ts +5 -1
- package/src/useGestureViewerState.ts +1 -0
- package/src/utils/index.ts +31 -15
package/src/useGestureViewer.ts
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
type NativeSyntheticEvent,
|
|
6
6
|
useWindowDimensions,
|
|
7
7
|
} from 'react-native';
|
|
8
|
-
import { Gesture } from 'react-native-gesture-handler';
|
|
8
|
+
import { Gesture, type GestureType } from 'react-native-gesture-handler';
|
|
9
9
|
import {
|
|
10
10
|
Easing,
|
|
11
11
|
interpolate,
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
withTiming,
|
|
17
17
|
} from 'react-native-reanimated';
|
|
18
18
|
import { scheduleOnRN } from 'react-native-worklets';
|
|
19
|
+
|
|
19
20
|
import type GestureViewerManager from './GestureViewerManager';
|
|
20
21
|
import { registry } from './GestureViewerRegistry';
|
|
21
22
|
import type { GestureViewerProps, TriggerRect } from './types';
|
|
@@ -56,6 +57,8 @@ export const useGestureViewer = <ItemT, LC>({
|
|
|
56
57
|
const width = customWidth || screenWidth;
|
|
57
58
|
const height = customHeight || screenHeight;
|
|
58
59
|
|
|
60
|
+
const dismissGestureRef = useRef<GestureType>(undefined);
|
|
61
|
+
|
|
59
62
|
const [isZoomed, setIsZoomed] = useState(false);
|
|
60
63
|
const [isRotated, setIsRotated] = useState(false);
|
|
61
64
|
const [isPinching, setIsPinching] = useState(false);
|
|
@@ -90,20 +93,21 @@ export const useGestureViewer = <ItemT, LC>({
|
|
|
90
93
|
const animationConfig = useMemo(
|
|
91
94
|
() => ({
|
|
92
95
|
duration: triggerAnimation?.duration ?? 300,
|
|
93
|
-
easing: triggerAnimation?.easing ?? Easing.bezier(0.25, 0.1, 0.25, 1
|
|
96
|
+
easing: triggerAnimation?.easing ?? Easing.bezier(0.25, 0.1, 0.25, 1),
|
|
94
97
|
reduceMotion: triggerAnimation?.reduceMotion,
|
|
95
98
|
}),
|
|
96
99
|
[triggerAnimation?.duration, triggerAnimation?.easing, triggerAnimation?.reduceMotion],
|
|
97
100
|
);
|
|
98
101
|
|
|
99
|
-
const dismissOptions = useMemo(
|
|
100
|
-
|
|
102
|
+
const dismissOptions = useMemo(
|
|
103
|
+
() => ({
|
|
101
104
|
enabled: dismiss?.enabled ?? true,
|
|
102
|
-
threshold: dismiss?.threshold ?? 80,
|
|
103
|
-
resistance: dismiss?.resistance ?? 2,
|
|
104
105
|
fadeBackdrop: dismiss?.fadeBackdrop ?? true,
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
resistance: dismiss?.resistance ?? 2,
|
|
107
|
+
threshold: dismiss?.threshold ?? 80,
|
|
108
|
+
}),
|
|
109
|
+
[dismiss?.enabled, dismiss?.threshold, dismiss?.resistance, dismiss?.fadeBackdrop],
|
|
110
|
+
);
|
|
107
111
|
|
|
108
112
|
const adjustedInitialIndex = useMemo(() => {
|
|
109
113
|
if (enableLoop && dataLength > 1) {
|
|
@@ -113,7 +117,10 @@ export const useGestureViewer = <ItemT, LC>({
|
|
|
113
117
|
return initialIndex;
|
|
114
118
|
}, [enableLoop, dataLength, initialIndex]);
|
|
115
119
|
|
|
116
|
-
const constrainTranslation = useMemo(
|
|
120
|
+
const constrainTranslation = useMemo(
|
|
121
|
+
() => createBoundsConstraint({ height, width }),
|
|
122
|
+
[width, height],
|
|
123
|
+
);
|
|
117
124
|
|
|
118
125
|
const scrollTo = useCallback(
|
|
119
126
|
(index: number, animated: boolean) => {
|
|
@@ -239,7 +246,16 @@ export const useGestureViewer = <ItemT, LC>({
|
|
|
239
246
|
return () => {
|
|
240
247
|
runAfterInteractions?.cancel();
|
|
241
248
|
};
|
|
242
|
-
}, [
|
|
249
|
+
}, [
|
|
250
|
+
adjustedInitialIndex,
|
|
251
|
+
translateY,
|
|
252
|
+
backdropOpacity,
|
|
253
|
+
translateX,
|
|
254
|
+
scale,
|
|
255
|
+
startScale,
|
|
256
|
+
rotation,
|
|
257
|
+
scrollTo,
|
|
258
|
+
]);
|
|
243
259
|
|
|
244
260
|
useEffect(() => {
|
|
245
261
|
if (
|
|
@@ -268,7 +284,16 @@ export const useGestureViewer = <ItemT, LC>({
|
|
|
268
284
|
}, intervalMs);
|
|
269
285
|
|
|
270
286
|
return () => clearInterval(interval);
|
|
271
|
-
}, [
|
|
287
|
+
}, [
|
|
288
|
+
autoPlay,
|
|
289
|
+
autoPlayInterval,
|
|
290
|
+
manager,
|
|
291
|
+
dataLength,
|
|
292
|
+
currentIndex,
|
|
293
|
+
enableLoop,
|
|
294
|
+
isZoomed,
|
|
295
|
+
isRotated,
|
|
296
|
+
]);
|
|
272
297
|
|
|
273
298
|
useEffect(() => {
|
|
274
299
|
onAnimationCompleteRef.current = triggerAnimation?.onAnimationComplete;
|
|
@@ -320,7 +345,7 @@ export const useGestureViewer = <ItemT, LC>({
|
|
|
320
345
|
|
|
321
346
|
if (node && typeof node.measure === 'function') {
|
|
322
347
|
node.measure((_x, _y, width, height, pageX, pageY) => {
|
|
323
|
-
triggerRectRef.current = { x: pageX, y: pageY
|
|
348
|
+
triggerRectRef.current = { height, width, x: pageX, y: pageY };
|
|
324
349
|
triggerOpacity.value = 0;
|
|
325
350
|
setShouldStartTriggerAnimation(true);
|
|
326
351
|
registry.clearTriggerNode(id);
|
|
@@ -338,7 +363,10 @@ export const useGestureViewer = <ItemT, LC>({
|
|
|
338
363
|
if (triggerRectRef.current) {
|
|
339
364
|
const endX = triggerRectRef.current.x + triggerRectRef.current.width / 2 - width / 2;
|
|
340
365
|
const endY = triggerRectRef.current.y + triggerRectRef.current.height / 2 - height / 2;
|
|
341
|
-
const endScale = Math.min(
|
|
366
|
+
const endScale = Math.min(
|
|
367
|
+
triggerRectRef.current.width / width,
|
|
368
|
+
triggerRectRef.current.height / height,
|
|
369
|
+
);
|
|
342
370
|
|
|
343
371
|
triggerScale.value = withTiming(endScale, animationConfig);
|
|
344
372
|
triggerTranslateX.value = withTiming(endX, animationConfig);
|
|
@@ -372,7 +400,7 @@ export const useGestureViewer = <ItemT, LC>({
|
|
|
372
400
|
return;
|
|
373
401
|
}
|
|
374
402
|
|
|
375
|
-
const contentOffset = event.nativeEvent
|
|
403
|
+
const { contentOffset } = event.nativeEvent;
|
|
376
404
|
const scrollIndex = Math.round(contentOffset.x / (width + itemSpacing));
|
|
377
405
|
|
|
378
406
|
const isLoopHandled = manager?.handleMomentumScrollEnd(scrollIndex);
|
|
@@ -381,7 +409,11 @@ export const useGestureViewer = <ItemT, LC>({
|
|
|
381
409
|
return;
|
|
382
410
|
}
|
|
383
411
|
|
|
384
|
-
const { realIndex, needsJump, jumpToIndex } = getLoopAdjustedIndex(
|
|
412
|
+
const { realIndex, needsJump, jumpToIndex } = getLoopAdjustedIndex(
|
|
413
|
+
scrollIndex,
|
|
414
|
+
dataLength,
|
|
415
|
+
enableLoop,
|
|
416
|
+
);
|
|
385
417
|
|
|
386
418
|
if (needsJump && jumpToIndex !== undefined) {
|
|
387
419
|
scrollTo(jumpToIndex, false);
|
|
@@ -431,6 +463,7 @@ export const useGestureViewer = <ItemT, LC>({
|
|
|
431
463
|
.activeCursor('grabbing')
|
|
432
464
|
.activeOffsetY([-10, 10])
|
|
433
465
|
.failOffsetX([-10, 10])
|
|
466
|
+
.withRef(dismissGestureRef)
|
|
434
467
|
.enabled(canDismiss)
|
|
435
468
|
.onUpdate((event) => {
|
|
436
469
|
translateY.value = event.translationY / dismissOptions.resistance;
|
|
@@ -442,221 +475,230 @@ export const useGestureViewer = <ItemT, LC>({
|
|
|
442
475
|
}
|
|
443
476
|
|
|
444
477
|
translateY.value = withSpring(0, {
|
|
445
|
-
stiffness: 600,
|
|
446
478
|
damping: 50,
|
|
479
|
+
energyThreshold: 6e-9,
|
|
447
480
|
mass: 4,
|
|
448
481
|
overshootClamping: false,
|
|
449
|
-
|
|
482
|
+
stiffness: 600,
|
|
450
483
|
});
|
|
451
484
|
});
|
|
452
485
|
}, [translateY, dismissOptions, handleDismiss, isZoomed]);
|
|
453
486
|
|
|
454
|
-
const zoomPinchGesture = useMemo(
|
|
455
|
-
|
|
456
|
-
.
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
lastFocalY.value = event.focalY;
|
|
468
|
-
})
|
|
469
|
-
.onUpdate((event) => {
|
|
470
|
-
const newScale = startScale.value * event.scale;
|
|
471
|
-
|
|
472
|
-
scale.value = newScale;
|
|
473
|
-
|
|
474
|
-
if (newScale <= 1) {
|
|
475
|
-
translateX.value = withTiming(0);
|
|
476
|
-
translateY.value = withTiming(0);
|
|
477
|
-
return;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
const focalDeltaX = Math.abs(event.focalX - lastFocalX.value);
|
|
481
|
-
const focalDeltaY = Math.abs(event.focalY - lastFocalY.value);
|
|
482
|
-
const threshold = 50;
|
|
483
|
-
|
|
484
|
-
if (focalDeltaX < threshold && focalDeltaY < threshold) {
|
|
487
|
+
const zoomPinchGesture = useMemo(
|
|
488
|
+
() =>
|
|
489
|
+
Gesture.Pinch()
|
|
490
|
+
.enabled(enablePinchZoom)
|
|
491
|
+
.onTouchesDown((event) => {
|
|
492
|
+
if (event.numberOfTouches === 2) {
|
|
493
|
+
scheduleOnRN(setIsPinching, true);
|
|
494
|
+
}
|
|
495
|
+
})
|
|
496
|
+
.onBegin((event) => {
|
|
497
|
+
startScale.value = scale.value;
|
|
498
|
+
initialTranslateX.value = translateX.value;
|
|
499
|
+
initialTranslateY.value = translateY.value;
|
|
485
500
|
lastFocalX.value = event.focalX;
|
|
486
501
|
lastFocalY.value = event.focalY;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
502
|
+
})
|
|
503
|
+
.onUpdate((event) => {
|
|
504
|
+
const newScale = startScale.value * event.scale;
|
|
505
|
+
|
|
506
|
+
scale.value = newScale;
|
|
507
|
+
|
|
508
|
+
if (newScale <= 1) {
|
|
509
|
+
translateX.value = withTiming(0);
|
|
510
|
+
translateY.value = withTiming(0);
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const focalDeltaX = Math.abs(event.focalX - lastFocalX.value);
|
|
515
|
+
const focalDeltaY = Math.abs(event.focalY - lastFocalY.value);
|
|
516
|
+
const threshold = 50;
|
|
517
|
+
|
|
518
|
+
if (focalDeltaX < threshold && focalDeltaY < threshold) {
|
|
519
|
+
lastFocalX.value = event.focalX;
|
|
520
|
+
lastFocalY.value = event.focalY;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const deltaScale = newScale - startScale.value;
|
|
524
|
+
const centerX = lastFocalX.value - width / 2;
|
|
525
|
+
const centerY = lastFocalY.value - height / 2;
|
|
526
|
+
|
|
527
|
+
// NOTE 새로운 이동값 = 기존 이동값 - (중심점 거리 × 스케일 변화량) / 원래 스케일 (중심점이 화면 중심에서 멀수록, 확대 배율이 클수록 더 많이 이동)
|
|
528
|
+
const newTranslateX = initialTranslateX.value - (centerX * deltaScale) / startScale.value;
|
|
529
|
+
const newTranslateY = initialTranslateY.value - (centerY * deltaScale) / startScale.value;
|
|
530
|
+
|
|
531
|
+
const { translateX: constrainedTranslateX, translateY: constrainedTranslateY } =
|
|
532
|
+
constrainTranslation({
|
|
533
|
+
scale: newScale,
|
|
534
|
+
translateX: newTranslateX,
|
|
535
|
+
translateY: newTranslateY,
|
|
536
|
+
});
|
|
492
537
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
538
|
+
translateX.value = constrainedTranslateX;
|
|
539
|
+
translateY.value = constrainedTranslateY;
|
|
540
|
+
})
|
|
541
|
+
.onEnd(() => {
|
|
542
|
+
if (scale.value > maxZoomScale) {
|
|
543
|
+
scale.value = withTiming(maxZoomScale, {
|
|
544
|
+
duration: 300,
|
|
545
|
+
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
const { translateX: constrainedTranslateX, translateY: constrainedTranslateY } =
|
|
549
|
+
constrainTranslation({
|
|
550
|
+
scale: maxZoomScale,
|
|
551
|
+
translateX: translateX.value,
|
|
552
|
+
translateY: translateY.value,
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
translateX.value = withTiming(constrainedTranslateX);
|
|
556
|
+
translateY.value = withTiming(constrainedTranslateY);
|
|
557
|
+
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
if (scale.value < 1) {
|
|
562
|
+
scale.value = withTiming(1, {
|
|
563
|
+
duration: 300,
|
|
564
|
+
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
|
|
565
|
+
});
|
|
566
|
+
translateX.value = withTiming(0);
|
|
567
|
+
translateY.value = withTiming(0);
|
|
568
|
+
initialTranslateX.value = withTiming(0);
|
|
569
|
+
initialTranslateY.value = withTiming(0);
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
const { translateX: constrainedTranslateX, translateY: constrainedTranslateY } =
|
|
574
|
+
constrainTranslation({
|
|
575
|
+
scale: scale.value,
|
|
576
|
+
translateX: translateX.value,
|
|
577
|
+
translateY: translateY.value,
|
|
578
|
+
});
|
|
518
579
|
|
|
519
580
|
translateX.value = withTiming(constrainedTranslateX);
|
|
520
581
|
translateY.value = withTiming(constrainedTranslateY);
|
|
582
|
+
})
|
|
583
|
+
.onTouchesUp(() => {
|
|
584
|
+
scheduleOnRN(setIsPinching, false);
|
|
585
|
+
})
|
|
586
|
+
.onFinalize(() => {
|
|
587
|
+
scheduleOnRN(setIsPinching, false);
|
|
588
|
+
}),
|
|
589
|
+
[
|
|
590
|
+
scale,
|
|
591
|
+
enablePinchZoom,
|
|
592
|
+
maxZoomScale,
|
|
593
|
+
translateX,
|
|
594
|
+
translateY,
|
|
595
|
+
startScale,
|
|
596
|
+
initialTranslateX,
|
|
597
|
+
initialTranslateY,
|
|
598
|
+
width,
|
|
599
|
+
height,
|
|
600
|
+
constrainTranslation,
|
|
601
|
+
lastFocalX,
|
|
602
|
+
lastFocalY,
|
|
603
|
+
],
|
|
604
|
+
);
|
|
521
605
|
|
|
522
|
-
|
|
523
|
-
|
|
606
|
+
const zoomPanGesture = useMemo(
|
|
607
|
+
() =>
|
|
608
|
+
Gesture.Pan()
|
|
609
|
+
.enabled(enablePanWhenZoomed && isZoomed)
|
|
610
|
+
.activeCursor('grabbing')
|
|
611
|
+
.averageTouches(true)
|
|
612
|
+
.onBegin(() => {
|
|
613
|
+
initialTranslateX.value = translateX.value;
|
|
614
|
+
initialTranslateY.value = translateY.value;
|
|
615
|
+
})
|
|
616
|
+
.onUpdate((event) => {
|
|
617
|
+
if (scale.value > 1) {
|
|
618
|
+
const newTranslateX = initialTranslateX.value + event.translationX;
|
|
619
|
+
const newTranslateY = initialTranslateY.value + event.translationY;
|
|
620
|
+
|
|
621
|
+
const { translateX: constrainedTranslateX, translateY: constrainedTranslateY } =
|
|
622
|
+
constrainTranslation({
|
|
623
|
+
scale: scale.value,
|
|
624
|
+
translateX: newTranslateX,
|
|
625
|
+
translateY: newTranslateY,
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
translateX.value = constrainedTranslateX;
|
|
629
|
+
translateY.value = constrainedTranslateY;
|
|
630
|
+
}
|
|
631
|
+
}),
|
|
632
|
+
[
|
|
633
|
+
translateX,
|
|
634
|
+
translateY,
|
|
635
|
+
enablePanWhenZoomed,
|
|
636
|
+
isZoomed,
|
|
637
|
+
scale,
|
|
638
|
+
initialTranslateX,
|
|
639
|
+
initialTranslateY,
|
|
640
|
+
constrainTranslation,
|
|
641
|
+
],
|
|
642
|
+
);
|
|
524
643
|
|
|
525
|
-
|
|
526
|
-
|
|
644
|
+
const doubleTapGesture = useMemo(
|
|
645
|
+
() =>
|
|
646
|
+
Gesture.Tap()
|
|
647
|
+
.enabled(enableDoubleTapZoom)
|
|
648
|
+
.numberOfTaps(2)
|
|
649
|
+
.onEnd((event) => {
|
|
650
|
+
const nextScale = scale.value > 1 ? 1 : maxZoomScale;
|
|
651
|
+
|
|
652
|
+
if (nextScale > 1) {
|
|
653
|
+
const centerX = event.x - width / 2;
|
|
654
|
+
const centerY = event.y - height / 2;
|
|
655
|
+
|
|
656
|
+
// NOTE 확대로 밀려난 거리만큼 반대로 이동해서 탭 지점을 제자리에 유지
|
|
657
|
+
translateX.value = withTiming(-centerX * (nextScale - 1), {
|
|
658
|
+
duration: 300,
|
|
659
|
+
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
|
|
660
|
+
});
|
|
661
|
+
translateY.value = withTiming(-centerY * (nextScale - 1), {
|
|
662
|
+
duration: 300,
|
|
663
|
+
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
|
|
664
|
+
});
|
|
665
|
+
} else {
|
|
666
|
+
translateX.value = withTiming(0, {
|
|
667
|
+
duration: 300,
|
|
668
|
+
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
|
|
669
|
+
});
|
|
670
|
+
translateY.value = withTiming(0, {
|
|
671
|
+
duration: 300,
|
|
672
|
+
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
scale.value = withTiming(nextScale, {
|
|
527
677
|
duration: 300,
|
|
528
|
-
easing: Easing.bezier(0.25, 0.1, 0.25, 1
|
|
678
|
+
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
|
|
529
679
|
});
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
initialTranslateY.value = withTiming(0);
|
|
534
|
-
return;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
const { translateX: constrainedTranslateX, translateY: constrainedTranslateY } = constrainTranslation({
|
|
538
|
-
translateX: translateX.value,
|
|
539
|
-
translateY: translateY.value,
|
|
540
|
-
scale: scale.value,
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
translateX.value = withTiming(constrainedTranslateX);
|
|
544
|
-
translateY.value = withTiming(constrainedTranslateY);
|
|
545
|
-
})
|
|
546
|
-
.onTouchesUp(() => {
|
|
547
|
-
scheduleOnRN(setIsPinching, false);
|
|
548
|
-
})
|
|
549
|
-
.onFinalize(() => {
|
|
550
|
-
scheduleOnRN(setIsPinching, false);
|
|
551
|
-
});
|
|
552
|
-
}, [
|
|
553
|
-
scale,
|
|
554
|
-
enablePinchZoom,
|
|
555
|
-
maxZoomScale,
|
|
556
|
-
translateX,
|
|
557
|
-
translateY,
|
|
558
|
-
startScale,
|
|
559
|
-
initialTranslateX,
|
|
560
|
-
initialTranslateY,
|
|
561
|
-
width,
|
|
562
|
-
height,
|
|
563
|
-
constrainTranslation,
|
|
564
|
-
lastFocalX,
|
|
565
|
-
lastFocalY,
|
|
566
|
-
]);
|
|
567
|
-
|
|
568
|
-
const zoomPanGesture = useMemo(() => {
|
|
569
|
-
return Gesture.Pan()
|
|
570
|
-
.enabled(enablePanWhenZoomed && isZoomed)
|
|
571
|
-
.activeCursor('grabbing')
|
|
572
|
-
.averageTouches(true)
|
|
573
|
-
.onBegin(() => {
|
|
574
|
-
initialTranslateX.value = translateX.value;
|
|
575
|
-
initialTranslateY.value = translateY.value;
|
|
576
|
-
})
|
|
577
|
-
.onUpdate((event) => {
|
|
578
|
-
if (scale.value > 1) {
|
|
579
|
-
const newTranslateX = initialTranslateX.value + event.translationX;
|
|
580
|
-
const newTranslateY = initialTranslateY.value + event.translationY;
|
|
581
|
-
|
|
582
|
-
const { translateX: constrainedTranslateX, translateY: constrainedTranslateY } = constrainTranslation({
|
|
583
|
-
translateX: newTranslateX,
|
|
584
|
-
translateY: newTranslateY,
|
|
585
|
-
scale: scale.value,
|
|
586
|
-
});
|
|
587
|
-
|
|
588
|
-
translateX.value = constrainedTranslateX;
|
|
589
|
-
translateY.value = constrainedTranslateY;
|
|
590
|
-
}
|
|
591
|
-
});
|
|
592
|
-
}, [
|
|
593
|
-
translateX,
|
|
594
|
-
translateY,
|
|
595
|
-
enablePanWhenZoomed,
|
|
596
|
-
isZoomed,
|
|
597
|
-
scale,
|
|
598
|
-
initialTranslateX,
|
|
599
|
-
initialTranslateY,
|
|
600
|
-
constrainTranslation,
|
|
601
|
-
]);
|
|
602
|
-
|
|
603
|
-
const doubleTapGesture = useMemo(() => {
|
|
604
|
-
return Gesture.Tap()
|
|
605
|
-
.enabled(enableDoubleTapZoom)
|
|
606
|
-
.numberOfTaps(2)
|
|
607
|
-
.onEnd((event) => {
|
|
608
|
-
const nextScale = scale.value > 1 ? 1 : maxZoomScale;
|
|
609
|
-
|
|
610
|
-
if (nextScale > 1) {
|
|
611
|
-
const centerX = event.x - width / 2;
|
|
612
|
-
const centerY = event.y - height / 2;
|
|
680
|
+
}),
|
|
681
|
+
[scale, enableDoubleTapZoom, maxZoomScale, translateX, translateY, width, height],
|
|
682
|
+
);
|
|
613
683
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
});
|
|
619
|
-
translateY.value = withTiming(-centerY * (nextScale - 1), {
|
|
620
|
-
duration: 300,
|
|
621
|
-
easing: Easing.bezier(0.25, 0.1, 0.25, 1.0),
|
|
622
|
-
});
|
|
623
|
-
} else {
|
|
624
|
-
translateX.value = withTiming(0, {
|
|
625
|
-
duration: 300,
|
|
626
|
-
easing: Easing.bezier(0.25, 0.1, 0.25, 1.0),
|
|
627
|
-
});
|
|
628
|
-
translateY.value = withTiming(0, {
|
|
629
|
-
duration: 300,
|
|
630
|
-
easing: Easing.bezier(0.25, 0.1, 0.25, 1.0),
|
|
631
|
-
});
|
|
632
|
-
}
|
|
684
|
+
const zoomGesture = useMemo(
|
|
685
|
+
() => Gesture.Race(zoomPinchGesture, Gesture.Exclusive(zoomPanGesture, doubleTapGesture)),
|
|
686
|
+
[zoomPinchGesture, zoomPanGesture, doubleTapGesture],
|
|
687
|
+
);
|
|
633
688
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
opacity: triggerOpacity.value,
|
|
648
|
-
transform: [
|
|
649
|
-
{ translateX: triggerTranslateX.value },
|
|
650
|
-
{ translateY: triggerTranslateY.value },
|
|
651
|
-
{ scale: triggerScale.value },
|
|
652
|
-
|
|
653
|
-
{ translateY: translateY.value },
|
|
654
|
-
{ translateX: translateX.value },
|
|
655
|
-
{ scale: scale.value },
|
|
656
|
-
{ rotate: `${rotation.value}deg` },
|
|
657
|
-
],
|
|
658
|
-
};
|
|
659
|
-
});
|
|
689
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
690
|
+
opacity: triggerOpacity.value,
|
|
691
|
+
transform: [
|
|
692
|
+
{ translateX: triggerTranslateX.value },
|
|
693
|
+
{ translateY: triggerTranslateY.value },
|
|
694
|
+
{ scale: triggerScale.value },
|
|
695
|
+
|
|
696
|
+
{ translateY: translateY.value },
|
|
697
|
+
{ translateX: translateX.value },
|
|
698
|
+
{ scale: scale.value },
|
|
699
|
+
{ rotate: `${rotation.value}deg` },
|
|
700
|
+
],
|
|
701
|
+
}));
|
|
660
702
|
|
|
661
703
|
const backdropStyle = useAnimatedStyle(() => {
|
|
662
704
|
const baseOpacity = triggerOpacity.value;
|
|
@@ -670,24 +712,29 @@ export const useGestureViewer = <ItemT, LC>({
|
|
|
670
712
|
return { opacity: baseOpacity * dismissOpacity };
|
|
671
713
|
}, [dismissOptions.fadeBackdrop]);
|
|
672
714
|
|
|
715
|
+
const nativeScrollGesture = useMemo(() => {
|
|
716
|
+
return Gesture.Native().requireExternalGestureToFail(dismissGestureRef);
|
|
717
|
+
}, []);
|
|
718
|
+
|
|
673
719
|
const onScrollBeginDrag = useCallback(() => {
|
|
674
720
|
manager?.handleScrollBeginDrag();
|
|
675
721
|
}, [manager]);
|
|
676
722
|
|
|
677
723
|
return {
|
|
724
|
+
animatedStyle,
|
|
725
|
+
backdropStyle,
|
|
678
726
|
dataLength,
|
|
679
|
-
listRef,
|
|
680
|
-
isZoomed,
|
|
681
|
-
isRotated,
|
|
682
|
-
isPinching,
|
|
683
727
|
dismissGesture,
|
|
684
|
-
|
|
728
|
+
handleDismiss,
|
|
729
|
+
isPinching,
|
|
730
|
+
isRotated,
|
|
685
731
|
|
|
732
|
+
isZoomed,
|
|
733
|
+
listRef,
|
|
734
|
+
nativeScrollGesture,
|
|
686
735
|
onMomentumScrollEnd,
|
|
687
|
-
onScrollBeginDrag,
|
|
688
|
-
handleDismiss,
|
|
689
736
|
|
|
690
|
-
|
|
691
|
-
|
|
737
|
+
onScrollBeginDrag,
|
|
738
|
+
zoomGesture,
|
|
692
739
|
};
|
|
693
740
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
|
+
|
|
2
3
|
import type GestureViewerManager from './GestureViewerManager';
|
|
3
4
|
import { registry } from './GestureViewerRegistry';
|
|
4
5
|
import type { GestureViewerEventCallback, GestureViewerEventType } from './types';
|
|
@@ -71,7 +72,10 @@ export function useGestureViewerEvent<T extends GestureViewerEventType>(
|
|
|
71
72
|
callback?: GestureViewerEventCallback<T>,
|
|
72
73
|
) {
|
|
73
74
|
const id = typeof idOrEventType === 'string' && callback ? idOrEventType : 'default';
|
|
74
|
-
const eventType =
|
|
75
|
+
const eventType =
|
|
76
|
+
typeof idOrEventType === 'string' && callback
|
|
77
|
+
? (eventTypeOrCallback as T)
|
|
78
|
+
: (idOrEventType as T);
|
|
75
79
|
const finalCallback = callback || (eventTypeOrCallback as GestureViewerEventCallback<T>);
|
|
76
80
|
|
|
77
81
|
useEffect(() => {
|