Fix flicker

Reanimated values and React props were out of sync. Prepare each image's styles separately to avoid that.
This commit is contained in:
Dan Abramov
2024-11-03 04:53:16 +00:00
parent 13b2c8f850
commit f261484d4c
+96 -55
View File
@@ -17,7 +17,7 @@ import {
StyleSheet,
View,
} from 'react-native'
import {Gesture} from 'react-native-gesture-handler'
import {Gesture, PanGesture} from 'react-native-gesture-handler'
import PagerView from 'react-native-pager-view'
import {
cancelAnimation,
@@ -108,47 +108,6 @@ function ImageViewing({
return {pointerEvents: 'auto'}
})
const activeInterpolation = useDerivedValue(() => {
const image = images[imageIndex]
if (image.thumbRect && image.dimensions) {
const interpolatedTransform = interpolateTransform(
openProgress.value,
image.thumbRect,
SCREEN,
image.dimensions,
)
return interpolatedTransform
}
})
const activeImageContainerStyle = useAnimatedStyle(() => {
if (openProgress.value === 1 || dismissSwipeTranslateY.value !== 0) {
return {
transform: [{translateY: dismissSwipeTranslateY.value}],
}
}
const interpolation = activeInterpolation.value
if (interpolation) {
return {
transform: interpolation.transform,
}
}
return {
transform: [],
}
})
const activeImageStyle = useAnimatedStyle(() => {
const interpolation = activeInterpolation.value
if (interpolation) {
return {
height: interpolation.height,
width: interpolation.width,
}
}
return {}
})
const dismissSwipePan = Gesture.Pan()
.enabled(!isScaled)
.activeOffsetY([-10, 10])
@@ -248,20 +207,21 @@ function ImageViewing({
overdrag={true}
style={styles.pager}>
{images.map((imageSrc, i) => (
<Animated.View
<LightboxPage
key={imageSrc.uri}
style={imageIndex === i ? activeImageContainerStyle : null}>
<ImageItem
onTap={onTap}
onZoom={onZoom}
imageSrc={imageSrc}
onRequestClose={onRequestClose}
isPagingAndroid={isPagingAndroid}
showControls={showControls}
dismissSwipePan={imageIndex === i ? dismissSwipePan : null}
imageStyle={imageIndex === i ? activeImageStyle : null}
/>
</Animated.View>
imageSrc={imageSrc}
onRequestClose={onRequestClose}
onTap={onTap}
onZoom={onZoom}
isActive={i === imageIndex}
isPagingAndroid={isPagingAndroid}
isFlyingAway={isFlyingAway}
isScaled={isScaled}
showControls={showControls}
openProgress={openProgress}
dismissSwipePan={dismissSwipePan}
dismissSwipeTranslateY={dismissSwipeTranslateY}
/>
))}
</PagerView>
<Animated.View style={[styles.footer, animatedFooterStyle]}>
@@ -277,6 +237,87 @@ function ImageViewing({
)
}
function LightboxPage({
imageSrc,
onRequestClose,
onTap,
onZoom,
isActive,
isPagingAndroid,
showControls,
openProgress,
dismissSwipeTranslateY,
dismissSwipePan,
}: {
imageSrc: ImageSource
onRequestClose: () => void
onTap: () => void
onZoom: (scaled: boolean) => void
isActive: boolean
isPagingAndroid: boolean
isFlyingAway: SharedValue<boolean>
isScaled: boolean
showControls: boolean
openProgress: SharedValue<number>
dismissSwipeTranslateY: SharedValue<number>
dismissSwipePan: PanGesture
}) {
const {thumbRect, dimensions} = imageSrc
const imageAspect = dimensions
? dimensions.width / dimensions.height
: undefined
const finalWidth = SCREEN.width
const finalHeight = imageAspect ? SCREEN.width / imageAspect : undefined
const interpolation = useDerivedValue(() => {
if (isActive && thumbRect && dimensions && openProgress.value < 1) {
return interpolateTransform(
openProgress.value,
thumbRect,
SCREEN,
dimensions,
)
}
const translateY = isActive ? dismissSwipeTranslateY.value : 0
return {
transform: [{translateY}],
width: finalWidth,
height: finalHeight,
}
})
const containerStyle = useAnimatedStyle(() => {
const {transform} = interpolation.value
return {
flex: 1,
transform,
}
})
const imageStyle = useAnimatedStyle(() => {
const {width, height} = interpolation.value
return {
width,
height,
}
})
return (
<Animated.View style={containerStyle}>
<ImageItem
onTap={onTap}
onZoom={onZoom}
imageSrc={imageSrc}
onRequestClose={onRequestClose}
isPagingAndroid={isPagingAndroid}
showControls={showControls}
dismissSwipePan={isActive ? dismissSwipePan : null}
imageStyle={imageStyle}
/>
</Animated.View>
)
}
function LightboxFooter({
images,
index,