"Contain" images with missing dimensions instead of cropping them (#6828)
* Show unknown aspect as "contain" for autosize * Fix a flash of wrong position when opening in lightbox * Fix last frame flash on Android
This commit is contained in:
@@ -392,9 +392,9 @@ const ImageItem = ({
|
|||||||
<Animated.View style={imageCropStyle}>
|
<Animated.View style={imageCropStyle}>
|
||||||
<Animated.View style={imageStyle}>
|
<Animated.View style={imageStyle}>
|
||||||
<Image
|
<Image
|
||||||
contentFit="cover"
|
contentFit="contain"
|
||||||
source={{uri: imageSrc.uri}}
|
source={{uri: imageSrc.uri}}
|
||||||
placeholderContentFit="cover"
|
placeholderContentFit="contain"
|
||||||
placeholder={{uri: imageSrc.thumbUri}}
|
placeholder={{uri: imageSrc.thumbUri}}
|
||||||
accessibilityLabel={imageSrc.alt}
|
accessibilityLabel={imageSrc.alt}
|
||||||
onLoad={
|
onLoad={
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// Original code copied and simplified from the link below as the codebase is currently not maintained:
|
// Original code copied and simplified from the link below as the codebase is currently not maintained:
|
||||||
// https://github.com/jobtoday/react-native-image-viewing
|
// https://github.com/jobtoday/react-native-image-viewing
|
||||||
|
|
||||||
import React, {useCallback, useEffect, useState} from 'react'
|
import React, {useCallback, useEffect, useMemo, useState} from 'react'
|
||||||
import {
|
import {
|
||||||
LayoutAnimation,
|
LayoutAnimation,
|
||||||
PixelRatio,
|
PixelRatio,
|
||||||
@@ -79,6 +79,15 @@ const FAST_SPRING: WithSpringConfig = {
|
|||||||
restDisplacementThreshold: 0.01,
|
restDisplacementThreshold: 0.01,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function canAnimate(lightbox: Lightbox): boolean {
|
||||||
|
return (
|
||||||
|
!PlatformInfo.getIsReducedMotionEnabled() &&
|
||||||
|
lightbox.images.every(
|
||||||
|
img => img.thumbRect && (img.dimensions || img.thumbDimensions),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default function ImageViewRoot({
|
export default function ImageViewRoot({
|
||||||
lightbox: nextLightbox,
|
lightbox: nextLightbox,
|
||||||
onRequestClose,
|
onRequestClose,
|
||||||
@@ -104,23 +113,19 @@ export default function ImageViewRoot({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const canAnimate =
|
const isAnimated = canAnimate(nextLightbox)
|
||||||
!PlatformInfo.getIsReducedMotionEnabled() &&
|
|
||||||
nextLightbox.images.every(
|
|
||||||
img => img.thumbRect && (img.dimensions || img.thumbDimensions),
|
|
||||||
)
|
|
||||||
|
|
||||||
// https://github.com/software-mansion/react-native-reanimated/issues/6677
|
// https://github.com/software-mansion/react-native-reanimated/issues/6677
|
||||||
rAF_FIXED(() => {
|
rAF_FIXED(() => {
|
||||||
openProgress.set(() =>
|
openProgress.set(() =>
|
||||||
canAnimate ? withClampedSpring(1, SLOW_SPRING) : 1,
|
isAnimated ? withClampedSpring(1, SLOW_SPRING) : 1,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
return () => {
|
return () => {
|
||||||
// https://github.com/software-mansion/react-native-reanimated/issues/6677
|
// https://github.com/software-mansion/react-native-reanimated/issues/6677
|
||||||
rAF_FIXED(() => {
|
rAF_FIXED(() => {
|
||||||
openProgress.set(() =>
|
openProgress.set(() =>
|
||||||
canAnimate ? withClampedSpring(0, SLOW_SPRING) : 0,
|
isAnimated ? withClampedSpring(0, SLOW_SPRING) : 0,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -185,6 +190,7 @@ function ImageView({
|
|||||||
openProgress: SharedValue<number>
|
openProgress: SharedValue<number>
|
||||||
}) {
|
}) {
|
||||||
const {images, index: initialImageIndex} = lightbox
|
const {images, index: initialImageIndex} = lightbox
|
||||||
|
const isAnimated = useMemo(() => canAnimate(lightbox), [lightbox])
|
||||||
const [isScaled, setIsScaled] = useState(false)
|
const [isScaled, setIsScaled] = useState(false)
|
||||||
const [isDragging, setIsDragging] = useState(false)
|
const [isDragging, setIsDragging] = useState(false)
|
||||||
const [imageIndex, setImageIndex] = useState(initialImageIndex)
|
const [imageIndex, setImageIndex] = useState(initialImageIndex)
|
||||||
@@ -194,10 +200,19 @@ function ImageView({
|
|||||||
const isFlyingAway = useSharedValue(false)
|
const isFlyingAway = useSharedValue(false)
|
||||||
|
|
||||||
const containerStyle = useAnimatedStyle(() => {
|
const containerStyle = useAnimatedStyle(() => {
|
||||||
if (openProgress.get() < 1 || isFlyingAway.get()) {
|
if (openProgress.get() < 1) {
|
||||||
return {pointerEvents: 'none'}
|
return {
|
||||||
|
pointerEvents: 'none',
|
||||||
|
opacity: isAnimated ? 1 : 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return {pointerEvents: 'auto'}
|
if (isFlyingAway.get()) {
|
||||||
|
return {
|
||||||
|
pointerEvents: 'none',
|
||||||
|
opacity: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {pointerEvents: 'auto', opacity: 1}
|
||||||
})
|
})
|
||||||
|
|
||||||
const backdropStyle = useAnimatedStyle(() => {
|
const backdropStyle = useAnimatedStyle(() => {
|
||||||
|
|||||||
@@ -85,10 +85,6 @@ export function AutoSizedImage({
|
|||||||
if (Number.isNaN(aspectRatio)) {
|
if (Number.isNaN(aspectRatio)) {
|
||||||
aspectRatio = undefined
|
aspectRatio = undefined
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// If we don't know it synchronously, treat it like a square.
|
|
||||||
// We won't use fetched dimensions to avoid a layout shift.
|
|
||||||
aspectRatio = 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let constrained: number | undefined
|
let constrained: number | undefined
|
||||||
@@ -103,11 +99,13 @@ export function AutoSizedImage({
|
|||||||
|
|
||||||
const cropDisabled = crop === 'none'
|
const cropDisabled = crop === 'none'
|
||||||
const isCropped = rawIsCropped && !cropDisabled
|
const isCropped = rawIsCropped && !cropDisabled
|
||||||
|
const isContain = aspectRatio === undefined
|
||||||
const hasAlt = !!image.alt
|
const hasAlt = !!image.alt
|
||||||
|
|
||||||
const contents = (
|
const contents = (
|
||||||
<View ref={containerRef} collapsable={false} style={{flex: 1}}>
|
<View ref={containerRef} collapsable={false} style={{flex: 1}}>
|
||||||
<Image
|
<Image
|
||||||
|
contentFit={isContain ? 'contain' : 'cover'}
|
||||||
style={[a.w_full, a.h_full]}
|
style={[a.w_full, a.h_full]}
|
||||||
source={image.thumb}
|
source={image.thumb}
|
||||||
accessible={true} // Must set for `accessibilityLabel` to work
|
accessible={true} // Must set for `accessibilityLabel` to work
|
||||||
@@ -115,9 +113,11 @@ export function AutoSizedImage({
|
|||||||
accessibilityLabel={image.alt}
|
accessibilityLabel={image.alt}
|
||||||
accessibilityHint=""
|
accessibilityHint=""
|
||||||
onLoad={e => {
|
onLoad={e => {
|
||||||
fetchedDimsRef.current = {
|
if (!isContain) {
|
||||||
width: e.source.width,
|
fetchedDimsRef.current = {
|
||||||
height: e.source.height,
|
width: e.source.width,
|
||||||
|
height: e.source.height,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user