From a48c213af585f43a1e6414ed0bf6c8d1552565d8 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 10 Oct 2023 23:48:31 +0100 Subject: [PATCH] Port remaining lightbox code to Reanimated (#1669) * Port remaining lightbox code to Reanimated * Fix memoization --- src/view/com/lightbox/ImageViewing/index.tsx | 69 ++++++++------------ 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/src/view/com/lightbox/ImageViewing/index.tsx b/src/view/com/lightbox/ImageViewing/index.tsx index 631a6ca0c0..78d16f8a62 100644 --- a/src/view/com/lightbox/ImageViewing/index.tsx +++ b/src/view/com/lightbox/ImageViewing/index.tsx @@ -8,13 +8,14 @@ // Original code copied and simplified from the link below as the codebase is currently not maintained: // https://github.com/jobtoday/react-native-image-viewing -import React, {ComponentType, useMemo, useState} from 'react' -import {Animated, StyleSheet, View, ModalProps, Platform} from 'react-native' +import React, {ComponentType, useCallback, useMemo, useState} from 'react' +import {StyleSheet, View, Platform} from 'react-native' import ImageItem from './components/ImageItem/ImageItem' import ImageDefaultHeader from './components/ImageDefaultHeader' import {ImageSource} from './@types' +import Animated, {useAnimatedStyle, withSpring} from 'react-native-reanimated' import {Edge, SafeAreaView} from 'react-native-safe-area-context' import PagerView from 'react-native-pager-view' @@ -23,19 +24,12 @@ type Props = { initialImageIndex: number visible: boolean onRequestClose: () => void - presentationStyle?: ModalProps['presentationStyle'] - animationType?: ModalProps['animationType'] backgroundColor?: string HeaderComponent?: ComponentType<{imageIndex: number}> FooterComponent?: ComponentType<{imageIndex: number}> } const DEFAULT_BG_COLOR = '#000' -const INITIAL_POSITION = {x: 0, y: 0} -const ANIMATION_CONFIG = { - duration: 200, - useNativeDriver: true, -} function ImageViewing({ images, @@ -49,37 +43,25 @@ function ImageViewing({ const [isScaled, setIsScaled] = useState(false) const [isDragging, setIsDragging] = useState(false) const [imageIndex, setImageIndex] = useState(initialImageIndex) - const [headerTranslate] = useState( - () => new Animated.ValueXY(INITIAL_POSITION), - ) - const [footerTranslate] = useState( - () => new Animated.ValueXY(INITIAL_POSITION), - ) - const toggleBarsVisible = (isVisible: boolean) => { - if (isVisible) { - Animated.parallel([ - Animated.timing(headerTranslate.y, {...ANIMATION_CONFIG, toValue: 0}), - Animated.timing(footerTranslate.y, {...ANIMATION_CONFIG, toValue: 0}), - ]).start() - } else { - Animated.parallel([ - Animated.timing(headerTranslate.y, { - ...ANIMATION_CONFIG, - toValue: -300, - }), - Animated.timing(footerTranslate.y, { - ...ANIMATION_CONFIG, - toValue: 300, - }), - ]).start() - } - } + const animatedHeaderStyle = useAnimatedStyle(() => ({ + transform: [ + { + translateY: withClampedSpring(isScaled ? -300 : 0), + }, + ], + })) + const animatedFooterStyle = useAnimatedStyle(() => ({ + transform: [ + { + translateY: withClampedSpring(isScaled ? 300 : 0), + }, + ], + })) - const onZoom = (nextIsScaled: boolean) => { - toggleBarsVisible(!nextIsScaled) - setIsScaled(false) - } + const onZoom = useCallback((nextIsScaled: boolean) => { + setIsScaled(nextIsScaled) + }, []) const edges = useMemo(() => { if (Platform.OS === 'android') { @@ -92,8 +74,6 @@ function ImageViewing({ return null } - const headerTransform = headerTranslate.getTranslateTransform() - const footerTransform = footerTranslate.getTranslateTransform() return ( - + {typeof HeaderComponent !== 'undefined' ? ( React.createElement(HeaderComponent, { imageIndex, @@ -134,7 +114,7 @@ function ImageViewing({ ))} {typeof FooterComponent !== 'undefined' && ( - + {React.createElement(FooterComponent, { imageIndex, })} @@ -179,4 +159,9 @@ const EnhancedImageViewing = (props: Props) => ( ) +function withClampedSpring(value: any) { + 'worklet' + return withSpring(value, {overshootClamping: true}) +} + export default EnhancedImageViewing