Fix layout jumps for images (#6474)

This commit is contained in:
dan
2024-11-18 21:42:32 +00:00
committed by GitHub
parent 924f1e0e7f
commit ec97352201
+15 -12
View File
@@ -1,4 +1,4 @@
import React from 'react' import React, {useRef} from 'react'
import {DimensionValue, Pressable, View} from 'react-native' import {DimensionValue, Pressable, View} from 'react-native'
import Animated, {AnimatedRef, useAnimatedRef} from 'react-native-reanimated' import Animated, {AnimatedRef, useAnimatedRef} from 'react-native-reanimated'
import {Image} from 'expo-image' import {Image} from 'expo-image'
@@ -79,15 +79,19 @@ export function AutoSizedImage({
const {_} = useLingui() const {_} = useLingui()
const largeAlt = useLargeAltBadgeEnabled() const largeAlt = useLargeAltBadgeEnabled()
const containerRef = useAnimatedRef() const containerRef = useAnimatedRef()
const fetchedDimsRef = useRef<{width: number; height: number} | null>(null)
const [fetchedDims, setFetchedDims] = React.useState<Dimensions | null>(null)
const dims = fetchedDims ?? image.aspectRatio
let aspectRatio: number | undefined let aspectRatio: number | undefined
const dims = image.aspectRatio
if (dims) { if (dims) {
aspectRatio = dims.width / dims.height aspectRatio = dims.width / dims.height
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
@@ -113,13 +117,12 @@ export function AutoSizedImage({
accessibilityIgnoresInvertColors accessibilityIgnoresInvertColors
accessibilityLabel={image.alt} accessibilityLabel={image.alt}
accessibilityHint="" accessibilityHint=""
onLoad={ onLoad={e => {
fetchedDims fetchedDimsRef.current = {
? undefined width: e.source.width,
: e => { height: e.source.height,
setFetchedDims({width: e.source.width, height: e.source.height}) }
} }}
}
/> />
<MediaInsetBorder /> <MediaInsetBorder />
@@ -191,7 +194,7 @@ export function AutoSizedImage({
if (cropDisabled) { if (cropDisabled) {
return ( return (
<Pressable <Pressable
onPress={() => onPress?.(containerRef, fetchedDims)} onPress={() => onPress?.(containerRef, fetchedDimsRef.current)}
onLongPress={onLongPress} onLongPress={onLongPress}
onPressIn={onPressIn} onPressIn={onPressIn}
// alt here is what screen readers actually use // alt here is what screen readers actually use
@@ -213,7 +216,7 @@ export function AutoSizedImage({
fullBleed={crop === 'square'} fullBleed={crop === 'square'}
aspectRatio={constrained ?? 1}> aspectRatio={constrained ?? 1}>
<Pressable <Pressable
onPress={() => onPress?.(containerRef, fetchedDims)} onPress={() => onPress?.(containerRef, fetchedDimsRef.current)}
onLongPress={onLongPress} onLongPress={onLongPress}
onPressIn={onPressIn} onPressIn={onPressIn}
// alt here is what screen readers actually use // alt here is what screen readers actually use