react-native-gesture-image-viewer 1.6.6 → 1.7.1
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 +39 -18
- package/lib/module/GestureTrigger.js +83 -0
- package/lib/module/GestureTrigger.js.map +1 -0
- package/lib/module/GestureViewer.js +8 -2
- package/lib/module/GestureViewer.js.map +1 -1
- package/lib/module/GestureViewerRegistry.js +15 -0
- package/lib/module/GestureViewerRegistry.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/useGestureViewer.js +100 -11
- package/lib/module/useGestureViewer.js.map +1 -1
- package/lib/typescript/src/GestureTrigger.d.ts +55 -0
- package/lib/typescript/src/GestureTrigger.d.ts.map +1 -0
- package/lib/typescript/src/GestureViewer.d.ts.map +1 -1
- package/lib/typescript/src/GestureViewerRegistry.d.ts +5 -0
- package/lib/typescript/src/GestureViewerRegistry.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +67 -12
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useGestureViewer.d.ts +9 -8
- package/lib/typescript/src/useGestureViewer.d.ts.map +1 -1
- package/package.json +14 -5
- package/src/GestureTrigger.tsx +90 -0
- package/src/GestureViewer.tsx +8 -2
- package/src/GestureViewerRegistry.ts +20 -0
- package/src/index.tsx +1 -0
- package/src/types.ts +67 -14
- package/src/useGestureViewer.ts +138 -11
package/src/types.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
import type { FlatList as RNFlatList, ScrollView as RNScrollView, StyleProp, ViewStyle } from 'react-native';
|
|
3
3
|
import type { FlatList as GHFlatList, ScrollView as GHScrollView } from 'react-native-gesture-handler';
|
|
4
|
+
import type { WithTimingConfig } from 'react-native-reanimated';
|
|
4
5
|
|
|
5
6
|
export type FlatListComponent = typeof RNFlatList | typeof GHFlatList;
|
|
6
7
|
export type ScrollViewComponent = typeof RNScrollView | typeof GHScrollView;
|
|
@@ -13,10 +14,34 @@ type ConditionalListProps<LC> = LC extends FlatListComponent
|
|
|
13
14
|
? React.ComponentProps<LC>
|
|
14
15
|
: GetComponentProps<LC>;
|
|
15
16
|
|
|
17
|
+
export type TriggerRect = {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export interface TriggerAnimationConfig extends WithTimingConfig {
|
|
25
|
+
/**
|
|
26
|
+
* Animation duration in milliseconds
|
|
27
|
+
* @defaultValue 300
|
|
28
|
+
*/
|
|
29
|
+
duration?: WithTimingConfig['duration'];
|
|
30
|
+
/**
|
|
31
|
+
* Animation easing function
|
|
32
|
+
* @defaultValue Easing.bezier(0.25, 0.1, 0.25, 1.0)
|
|
33
|
+
*/
|
|
34
|
+
easing?: WithTimingConfig['easing'];
|
|
35
|
+
/**
|
|
36
|
+
* Callback function called after animation completion
|
|
37
|
+
*/
|
|
38
|
+
onAnimationComplete?: () => void;
|
|
39
|
+
}
|
|
40
|
+
|
|
16
41
|
export interface GestureViewerProps<T = any, LC = typeof RNFlatList> {
|
|
17
42
|
/**
|
|
18
43
|
* When you want to efficiently manage multiple `GestureViewer` instances, you can use the `id` prop to use multiple `GestureViewer` components.
|
|
19
|
-
* @
|
|
44
|
+
* @remarks `GestureViewer` automatically removes instances from memory when components are unmounted, so no manual memory management is required.
|
|
20
45
|
* @defaultValue 'default'
|
|
21
46
|
*/
|
|
22
47
|
id?: string;
|
|
@@ -37,28 +62,39 @@ export interface GestureViewerProps<T = any, LC = typeof RNFlatList> {
|
|
|
37
62
|
* A callback function that is called when the `GestureViewer` is dismissed.
|
|
38
63
|
*/
|
|
39
64
|
onDismiss?: () => void;
|
|
65
|
+
/**
|
|
66
|
+
* A callback function that is called when the dismiss interaction starts.
|
|
67
|
+
* @remarks Useful to hide external UI (e.g., headers, buttons) while the dismiss gesture/animation is in progress.
|
|
68
|
+
*/
|
|
69
|
+
onDismissStart?: () => void;
|
|
40
70
|
/**
|
|
41
71
|
* A callback function that is called to render the item.
|
|
42
72
|
*/
|
|
43
73
|
renderItem: (item: T, index: number) => React.ReactElement;
|
|
44
74
|
/**
|
|
45
75
|
* A callback function that is called to render the container.
|
|
76
|
+
* @remarks Useful for composing additional UI (e.g., close button, toolbars) around the viewer.
|
|
77
|
+
* The second argument provides control helpers such as `dismiss()` to close the viewer.
|
|
78
|
+
*
|
|
79
|
+
* @param children - The viewer content to be rendered inside your container.
|
|
80
|
+
* @param helpers - Control helpers for the viewer. Currently includes `dismiss()`.
|
|
81
|
+
* @returns A React element that wraps and renders the provided `children`.
|
|
46
82
|
*/
|
|
47
|
-
renderContainer?: (children: React.ReactElement) => React.ReactElement;
|
|
83
|
+
renderContainer?: (children: React.ReactElement, helpers: { dismiss: () => void }) => React.ReactElement;
|
|
48
84
|
/**
|
|
49
85
|
* Support for any list component like `ScrollView`, `FlatList`, `FlashList` through the `ListComponent` prop.
|
|
50
86
|
*/
|
|
51
87
|
ListComponent: LC;
|
|
52
88
|
/**
|
|
53
89
|
* The width of the `GestureViewer`.
|
|
54
|
-
* @
|
|
90
|
+
* @remarks If you don't set this prop, the width of the `GestureViewer` will be the same as the width of the screen.
|
|
55
91
|
* @defaultValue screen width
|
|
56
92
|
*/
|
|
57
93
|
width?: number;
|
|
58
94
|
/**
|
|
59
95
|
* Enables snap scrolling mode.
|
|
60
96
|
*
|
|
61
|
-
* @
|
|
97
|
+
* @remarks
|
|
62
98
|
* **`false` (default)**: Paging mode (`pagingEnabled: true`)
|
|
63
99
|
* - Scrolls by full screen size increments
|
|
64
100
|
*
|
|
@@ -74,17 +110,15 @@ export interface GestureViewerProps<T = any, LC = typeof RNFlatList> {
|
|
|
74
110
|
* @defaultValue 80
|
|
75
111
|
*/
|
|
76
112
|
dismissThreshold?: number;
|
|
77
|
-
// swipeThreshold?: number;
|
|
78
|
-
// velocityThreshold?: number;
|
|
79
113
|
/**
|
|
80
114
|
* Calls `onDismiss` function when swiping down.
|
|
81
|
-
* @
|
|
115
|
+
* @remarks Useful for closing modals with downward swipe gestures.
|
|
82
116
|
* @defaultValue true
|
|
83
117
|
*/
|
|
84
118
|
enableDismissGesture?: boolean;
|
|
85
119
|
/**
|
|
86
120
|
* Controls left/right swipe gestures.
|
|
87
|
-
* @
|
|
121
|
+
* @remarks When `false`, horizontal gestures are disabled.
|
|
88
122
|
* @defaultValue true
|
|
89
123
|
*/
|
|
90
124
|
enableSwipeGesture?: boolean;
|
|
@@ -95,7 +129,7 @@ export interface GestureViewerProps<T = any, LC = typeof RNFlatList> {
|
|
|
95
129
|
resistance?: number;
|
|
96
130
|
/**
|
|
97
131
|
* The props to pass to the list component.
|
|
98
|
-
* @
|
|
132
|
+
* @remarks The `listProps` provides **type inference based on the selected list component**, ensuring accurate autocompletion and type safety in your IDE.
|
|
99
133
|
*/
|
|
100
134
|
listProps?: Partial<ConditionalListProps<LC>>;
|
|
101
135
|
/**
|
|
@@ -108,25 +142,25 @@ export interface GestureViewerProps<T = any, LC = typeof RNFlatList> {
|
|
|
108
142
|
containerStyle?: StyleProp<ViewStyle>;
|
|
109
143
|
/**
|
|
110
144
|
* By default, the background `opacity` gradually decreases from 1 to 0 during downward swipe gestures.
|
|
111
|
-
* @
|
|
145
|
+
* @remarks When `false`, this animation is disabled.
|
|
112
146
|
* @defaultValue true
|
|
113
147
|
*/
|
|
114
148
|
animateBackdrop?: boolean;
|
|
115
149
|
/**
|
|
116
150
|
* Only works when zoom is active, allows moving item position when zoomed.
|
|
117
|
-
* @
|
|
151
|
+
* @remarks When `false`, gesture movement is disabled during zoom.
|
|
118
152
|
* @defaultValue true
|
|
119
153
|
*/
|
|
120
154
|
enableZoomPanGesture?: boolean;
|
|
121
155
|
/**
|
|
122
156
|
* Controls two-finger pinch gestures.
|
|
123
|
-
* @
|
|
157
|
+
* @remarks When `false`, two-finger zoom gestures are disabled.
|
|
124
158
|
* @defaultValue true
|
|
125
159
|
*/
|
|
126
160
|
enableZoomGesture?: boolean;
|
|
127
161
|
/**
|
|
128
162
|
* Controls double-tap zoom gestures.
|
|
129
|
-
* @
|
|
163
|
+
* @remarks When `false`, double-tap zoom gestures are disabled.
|
|
130
164
|
* @defaultValue true
|
|
131
165
|
*/
|
|
132
166
|
enableDoubleTapGesture?: boolean;
|
|
@@ -142,10 +176,29 @@ export interface GestureViewerProps<T = any, LC = typeof RNFlatList> {
|
|
|
142
176
|
maxZoomScale?: number;
|
|
143
177
|
/**
|
|
144
178
|
* The spacing between items in pixels.
|
|
145
|
-
* @
|
|
179
|
+
* @remarks Only applied when `useSnap` is `true`.
|
|
146
180
|
* @defaultValue 0
|
|
147
181
|
*/
|
|
148
182
|
itemSpacing?: number;
|
|
183
|
+
/**
|
|
184
|
+
* Trigger-based animation settings
|
|
185
|
+
* @remarks You can customize animation duration, easing, and system reduce-motion behavior.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```tsx
|
|
189
|
+
* <GestureViewer
|
|
190
|
+
* triggerAnimation={{
|
|
191
|
+
* duration: 250,
|
|
192
|
+
* easing: Easing.out(Easing.cubic),
|
|
193
|
+
* reduceMotion: 'system',
|
|
194
|
+
* onAnimationComplete: () => {
|
|
195
|
+
* console.log('Animation complete');
|
|
196
|
+
* },
|
|
197
|
+
* }}
|
|
198
|
+
* />
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
triggerAnimation?: TriggerAnimationConfig;
|
|
149
202
|
}
|
|
150
203
|
|
|
151
204
|
/**
|
package/src/useGestureViewer.ts
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
} from 'react-native-reanimated';
|
|
19
19
|
import type GestureViewerManager from './GestureViewerManager';
|
|
20
20
|
import { registry } from './GestureViewerRegistry';
|
|
21
|
-
import type { GestureViewerProps } from './types';
|
|
21
|
+
import type { GestureViewerProps, TriggerRect } from './types';
|
|
22
22
|
import { createBoundsConstraint, createScrollAction, getLoopAdjustedIndex } from './utils';
|
|
23
23
|
|
|
24
24
|
type UseGestureViewerProps<T = any> = Omit<
|
|
@@ -34,8 +34,6 @@ export const useGestureViewer = <T = any>({
|
|
|
34
34
|
width: customWidth,
|
|
35
35
|
dismissThreshold = 80,
|
|
36
36
|
resistance = 2,
|
|
37
|
-
// swipeThreshold = 0.5,
|
|
38
|
-
// velocityThreshold = 200,
|
|
39
37
|
animateBackdrop = true,
|
|
40
38
|
enableDismissGesture = true,
|
|
41
39
|
enableSwipeGesture = true,
|
|
@@ -47,6 +45,8 @@ export const useGestureViewer = <T = any>({
|
|
|
47
45
|
itemSpacing = 0,
|
|
48
46
|
useSnap = false,
|
|
49
47
|
id = 'default',
|
|
48
|
+
onDismissStart,
|
|
49
|
+
triggerAnimation,
|
|
50
50
|
}: UseGestureViewerProps<T>) => {
|
|
51
51
|
const { width: screenWidth, height: screenHeight } = useWindowDimensions();
|
|
52
52
|
const width = useSnap ? customWidth || screenWidth : screenWidth;
|
|
@@ -54,11 +54,14 @@ export const useGestureViewer = <T = any>({
|
|
|
54
54
|
const [isZoomed, setIsZoomed] = useState(false);
|
|
55
55
|
const [isRotated, setIsRotated] = useState(false);
|
|
56
56
|
const [manager, setManager] = useState<GestureViewerManager | null>(null);
|
|
57
|
+
const [shouldStartTriggerAnimation, setShouldStartTriggerAnimation] = useState(false);
|
|
57
58
|
|
|
58
59
|
const listRef = useRef<any>(null);
|
|
59
60
|
const unsubscribeRef = useRef<(() => void) | null>(null);
|
|
60
61
|
const onIndexChangeRef = useRef<((index: number) => void) | null>(null);
|
|
61
62
|
const lastEmittedIndexRef = useRef<number>(null);
|
|
63
|
+
const triggerRectRef = useRef<TriggerRect | null>(null);
|
|
64
|
+
const onAnimationCompleteRef = useRef(triggerAnimation?.onAnimationComplete);
|
|
62
65
|
|
|
63
66
|
const initialTranslateY = useSharedValue(0);
|
|
64
67
|
const initialTranslateX = useSharedValue(0);
|
|
@@ -70,8 +73,22 @@ export const useGestureViewer = <T = any>({
|
|
|
70
73
|
const backdropOpacity = useSharedValue(1);
|
|
71
74
|
const rotation = useSharedValue(0);
|
|
72
75
|
|
|
76
|
+
const triggerScale = useSharedValue(1);
|
|
77
|
+
const triggerTranslateX = useSharedValue(0);
|
|
78
|
+
const triggerTranslateY = useSharedValue(0);
|
|
79
|
+
const triggerOpacity = useSharedValue(1);
|
|
80
|
+
|
|
73
81
|
const dataLength = data?.length || 0;
|
|
74
82
|
|
|
83
|
+
const animationConfig = useMemo(
|
|
84
|
+
() => ({
|
|
85
|
+
duration: triggerAnimation?.duration ?? 300,
|
|
86
|
+
easing: triggerAnimation?.easing ?? Easing.bezier(0.25, 0.1, 0.25, 1.0),
|
|
87
|
+
reduceMotion: triggerAnimation?.reduceMotion,
|
|
88
|
+
}),
|
|
89
|
+
[triggerAnimation?.duration, triggerAnimation?.easing, triggerAnimation?.reduceMotion],
|
|
90
|
+
);
|
|
91
|
+
|
|
75
92
|
const adjustedInitialIndex = useMemo(() => {
|
|
76
93
|
if (enableLoop && data.length > 1) {
|
|
77
94
|
return initialIndex + 1;
|
|
@@ -85,6 +102,10 @@ export const useGestureViewer = <T = any>({
|
|
|
85
102
|
[width, screenHeight],
|
|
86
103
|
);
|
|
87
104
|
|
|
105
|
+
const onAnimationComplete = useCallback(() => {
|
|
106
|
+
onAnimationCompleteRef.current?.();
|
|
107
|
+
}, []);
|
|
108
|
+
|
|
88
109
|
const scrollTo = useCallback(
|
|
89
110
|
(index: number, animated: boolean) => {
|
|
90
111
|
const scrollAction = createScrollAction(listRef.current, width + itemSpacing);
|
|
@@ -140,6 +161,68 @@ export const useGestureViewer = <T = any>({
|
|
|
140
161
|
};
|
|
141
162
|
}, []);
|
|
142
163
|
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
onAnimationCompleteRef.current = triggerAnimation?.onAnimationComplete;
|
|
166
|
+
}, [triggerAnimation?.onAnimationComplete]);
|
|
167
|
+
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
if (shouldStartTriggerAnimation && triggerRectRef.current) {
|
|
170
|
+
const startX = triggerRectRef.current.x + triggerRectRef.current.width / 2 - screenWidth / 2;
|
|
171
|
+
const startY = triggerRectRef.current.y + triggerRectRef.current.height / 2 - screenHeight / 2;
|
|
172
|
+
const initialScaleFromTrigger = Math.min(
|
|
173
|
+
triggerRectRef.current.width / screenWidth,
|
|
174
|
+
triggerRectRef.current.height / screenHeight,
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
triggerScale.value = initialScaleFromTrigger;
|
|
178
|
+
triggerTranslateX.value = startX;
|
|
179
|
+
triggerTranslateY.value = startY;
|
|
180
|
+
triggerOpacity.value = 0;
|
|
181
|
+
|
|
182
|
+
triggerScale.value = withTiming(1, animationConfig, (finished) => {
|
|
183
|
+
if (finished) {
|
|
184
|
+
runOnJS(onAnimationComplete)();
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
triggerTranslateX.value = withTiming(0, animationConfig);
|
|
188
|
+
triggerTranslateY.value = withTiming(0, animationConfig);
|
|
189
|
+
triggerOpacity.value = withTiming(1, {
|
|
190
|
+
duration: animationConfig.duration / 2,
|
|
191
|
+
easing: animationConfig.easing,
|
|
192
|
+
reduceMotion: animationConfig.reduceMotion,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
setShouldStartTriggerAnimation(false);
|
|
196
|
+
}
|
|
197
|
+
}, [
|
|
198
|
+
shouldStartTriggerAnimation,
|
|
199
|
+
animationConfig,
|
|
200
|
+
screenWidth,
|
|
201
|
+
screenHeight,
|
|
202
|
+
triggerOpacity,
|
|
203
|
+
triggerScale,
|
|
204
|
+
triggerTranslateX,
|
|
205
|
+
triggerTranslateY,
|
|
206
|
+
onAnimationComplete,
|
|
207
|
+
]);
|
|
208
|
+
|
|
209
|
+
useEffect(() => {
|
|
210
|
+
const node = registry.getTriggerNode(id);
|
|
211
|
+
|
|
212
|
+
if (node && typeof node.measure === 'function') {
|
|
213
|
+
node.measure((_x, _y, width, height, pageX, pageY) => {
|
|
214
|
+
triggerRectRef.current = { x: pageX, y: pageY, width, height };
|
|
215
|
+
triggerOpacity.value = 0;
|
|
216
|
+
setShouldStartTriggerAnimation(true);
|
|
217
|
+
registry.clearTriggerNode(id);
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return () => {
|
|
222
|
+
triggerRectRef.current = null;
|
|
223
|
+
};
|
|
224
|
+
}, [id, triggerOpacity]);
|
|
225
|
+
|
|
143
226
|
useEffect(() => {
|
|
144
227
|
const handleManagerChange = (manager: GestureViewerManager | null) => {
|
|
145
228
|
unsubscribeRef.current?.();
|
|
@@ -227,6 +310,43 @@ export const useGestureViewer = <T = any>({
|
|
|
227
310
|
};
|
|
228
311
|
}, [adjustedInitialIndex, translateY, backdropOpacity, translateX, scale, startScale, rotation, scrollTo]);
|
|
229
312
|
|
|
313
|
+
const handleDismiss = useCallback(() => {
|
|
314
|
+
onDismissStart?.();
|
|
315
|
+
|
|
316
|
+
if (triggerRectRef.current) {
|
|
317
|
+
const endX = triggerRectRef.current.x + triggerRectRef.current.width / 2 - screenWidth / 2;
|
|
318
|
+
const endY = triggerRectRef.current.y + triggerRectRef.current.height / 2 - screenHeight / 2;
|
|
319
|
+
const endScale = Math.min(
|
|
320
|
+
triggerRectRef.current.width / screenWidth,
|
|
321
|
+
triggerRectRef.current.height / screenHeight,
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
triggerScale.value = withTiming(endScale, animationConfig);
|
|
325
|
+
triggerTranslateX.value = withTiming(endX, animationConfig);
|
|
326
|
+
triggerTranslateY.value = withTiming(endY, animationConfig);
|
|
327
|
+
triggerOpacity.value = withTiming(0, animationConfig, (finished) => {
|
|
328
|
+
if (finished && onDismiss) {
|
|
329
|
+
runOnJS(onDismiss)();
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (onDismiss) {
|
|
336
|
+
runOnJS(onDismiss)();
|
|
337
|
+
}
|
|
338
|
+
}, [
|
|
339
|
+
animationConfig,
|
|
340
|
+
onDismiss,
|
|
341
|
+
onDismissStart,
|
|
342
|
+
screenWidth,
|
|
343
|
+
screenHeight,
|
|
344
|
+
triggerTranslateX,
|
|
345
|
+
triggerScale,
|
|
346
|
+
triggerTranslateY,
|
|
347
|
+
triggerOpacity,
|
|
348
|
+
]);
|
|
349
|
+
|
|
230
350
|
const onMomentumScrollEnd = useCallback(
|
|
231
351
|
(event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
232
352
|
if (!enableSwipeGesture) {
|
|
@@ -248,7 +368,7 @@ export const useGestureViewer = <T = any>({
|
|
|
248
368
|
scrollTo(jumpToIndex, false);
|
|
249
369
|
}
|
|
250
370
|
|
|
251
|
-
const currentIndex = manager?.getState()
|
|
371
|
+
const currentIndex = manager?.getState().currentIndex;
|
|
252
372
|
|
|
253
373
|
if (realIndex !== currentIndex && realIndex >= 0 && realIndex < dataLength) {
|
|
254
374
|
if (manager) {
|
|
@@ -297,8 +417,8 @@ export const useGestureViewer = <T = any>({
|
|
|
297
417
|
translateY.value = event.translationY / resistance;
|
|
298
418
|
})
|
|
299
419
|
.onEnd((event) => {
|
|
300
|
-
if (canDismiss && event.translationY > dismissThreshold &&
|
|
301
|
-
runOnJS(
|
|
420
|
+
if (canDismiss && event.translationY > dismissThreshold && handleDismiss) {
|
|
421
|
+
runOnJS(handleDismiss)();
|
|
302
422
|
return;
|
|
303
423
|
}
|
|
304
424
|
|
|
@@ -307,7 +427,7 @@ export const useGestureViewer = <T = any>({
|
|
|
307
427
|
stiffness: 150,
|
|
308
428
|
});
|
|
309
429
|
});
|
|
310
|
-
}, [translateY, dismissThreshold, enableDismissGesture,
|
|
430
|
+
}, [translateY, dismissThreshold, enableDismissGesture, handleDismiss, resistance, isZoomed]);
|
|
311
431
|
|
|
312
432
|
const zoomPinchGesture = useMemo(() => {
|
|
313
433
|
return Gesture.Pinch()
|
|
@@ -478,7 +598,12 @@ export const useGestureViewer = <T = any>({
|
|
|
478
598
|
|
|
479
599
|
const animatedStyle = useAnimatedStyle(() => {
|
|
480
600
|
return {
|
|
601
|
+
opacity: triggerOpacity.value,
|
|
481
602
|
transform: [
|
|
603
|
+
{ translateX: triggerTranslateX.value },
|
|
604
|
+
{ translateY: triggerTranslateY.value },
|
|
605
|
+
{ scale: triggerScale.value },
|
|
606
|
+
|
|
482
607
|
{ translateY: translateY.value },
|
|
483
608
|
{ translateX: translateX.value },
|
|
484
609
|
{ scale: scale.value },
|
|
@@ -488,13 +613,15 @@ export const useGestureViewer = <T = any>({
|
|
|
488
613
|
});
|
|
489
614
|
|
|
490
615
|
const backdropStyle = useAnimatedStyle(() => {
|
|
616
|
+
const baseOpacity = triggerOpacity.value;
|
|
617
|
+
|
|
491
618
|
if (!animateBackdrop || scale.value !== 1) {
|
|
492
|
-
return { opacity:
|
|
619
|
+
return { opacity: baseOpacity };
|
|
493
620
|
}
|
|
494
621
|
|
|
495
|
-
const
|
|
622
|
+
const dismissOpacity = interpolate(translateY.value, [0, 200], [1, 0], 'clamp');
|
|
496
623
|
|
|
497
|
-
return { opacity };
|
|
624
|
+
return { opacity: dismissOpacity * baseOpacity };
|
|
498
625
|
}, [animateBackdrop]);
|
|
499
626
|
|
|
500
627
|
const onScrollBeginDrag = useCallback(() => {
|
|
@@ -503,7 +630,6 @@ export const useGestureViewer = <T = any>({
|
|
|
503
630
|
|
|
504
631
|
return {
|
|
505
632
|
dataLength,
|
|
506
|
-
translateY,
|
|
507
633
|
listRef,
|
|
508
634
|
isZoomed,
|
|
509
635
|
isRotated,
|
|
@@ -512,6 +638,7 @@ export const useGestureViewer = <T = any>({
|
|
|
512
638
|
|
|
513
639
|
onMomentumScrollEnd,
|
|
514
640
|
onScrollBeginDrag,
|
|
641
|
+
handleDismiss,
|
|
515
642
|
|
|
516
643
|
animatedStyle,
|
|
517
644
|
backdropStyle,
|