Remove null checks for measurements

This commit is contained in:
Dan Abramov
2024-11-07 11:23:26 +00:00
parent d087565813
commit 0110552183
4 changed files with 66 additions and 36 deletions
@@ -1,13 +1,11 @@
import React, {useState} from 'react' import React, {useState} from 'react'
import {ActivityIndicator, StyleProp, StyleSheet, View} from 'react-native' import {ActivityIndicator, StyleProp, StyleSheet} from 'react-native'
import { import {
Gesture, Gesture,
GestureDetector, GestureDetector,
PanGesture, PanGesture,
} from 'react-native-gesture-handler' } from 'react-native-gesture-handler'
import Animated, { import Animated, {
AnimatedRef,
measure,
runOnJS, runOnJS,
useAnimatedReaction, useAnimatedReaction,
useAnimatedRef, useAnimatedRef,
@@ -42,7 +40,12 @@ type Props = {
onZoom: (isZoomed: boolean) => void onZoom: (isZoomed: boolean) => void
isScrollViewBeingDragged: boolean isScrollViewBeingDragged: boolean
showControls: boolean showControls: boolean
safeAreaRef: AnimatedRef<View> measureSafeArea: () => {
x: number
y: number
width: number
height: number
}
imageAspect: number | undefined imageAspect: number | undefined
imageDimensions: ImageDimensions | undefined imageDimensions: ImageDimensions | undefined
imageStyle: StyleProp<ImageStyle> imageStyle: StyleProp<ImageStyle>
@@ -53,7 +56,7 @@ const ImageItem = ({
onTap, onTap,
onZoom, onZoom,
isScrollViewBeingDragged, isScrollViewBeingDragged,
safeAreaRef, measureSafeArea,
imageAspect, imageAspect,
imageDimensions, imageDimensions,
imageStyle, imageStyle,
@@ -143,10 +146,7 @@ const ImageItem = ({
const pinch = Gesture.Pinch() const pinch = Gesture.Pinch()
.onStart(e => { .onStart(e => {
'worklet' 'worklet'
const screenSize = measure(safeAreaRef) const screenSize = measureSafeArea()
if (!screenSize) {
return
}
pinchOrigin.value = { pinchOrigin.value = {
x: e.focalX - screenSize.width / 2, x: e.focalX - screenSize.width / 2,
y: e.focalY - screenSize.height / 2, y: e.focalY - screenSize.height / 2,
@@ -154,8 +154,8 @@ const ImageItem = ({
}) })
.onChange(e => { .onChange(e => {
'worklet' 'worklet'
const screenSize = measure(safeAreaRef) const screenSize = measureSafeArea()
if (!imageDimensions || !screenSize) { if (!imageDimensions) {
return return
} }
// Don't let the picture zoom in so close that it gets blurry. // Don't let the picture zoom in so close that it gets blurry.
@@ -213,8 +213,8 @@ const ImageItem = ({
.minPointers(isScaled ? 1 : 2) .minPointers(isScaled ? 1 : 2)
.onChange(e => { .onChange(e => {
'worklet' 'worklet'
const screenSize = measure(safeAreaRef) const screenSize = measureSafeArea()
if (!imageDimensions || !screenSize) { if (!imageDimensions) {
return return
} }
@@ -257,8 +257,8 @@ const ImageItem = ({
.numberOfTaps(2) .numberOfTaps(2)
.onEnd(e => { .onEnd(e => {
'worklet' 'worklet'
const screenSize = measure(safeAreaRef) const screenSize = measureSafeArea()
if (!imageDimensions || !imageAspect || !screenSize) { if (!imageDimensions || !imageAspect) {
return return
} }
const [, , committedScale] = readTransform(committedTransform.value) const [, , committedScale] = readTransform(committedTransform.value)
@@ -7,18 +7,13 @@
*/ */
import React, {useState} from 'react' import React, {useState} from 'react'
import {ActivityIndicator, StyleProp, StyleSheet, View} from 'react-native' import {ActivityIndicator, StyleProp, StyleSheet} from 'react-native'
import { import {
Gesture, Gesture,
GestureDetector, GestureDetector,
PanGesture, PanGesture,
} from 'react-native-gesture-handler' } from 'react-native-gesture-handler'
import Animated, { import Animated, {runOnJS, useAnimatedRef} from 'react-native-reanimated'
AnimatedRef,
measure,
runOnJS,
useAnimatedRef,
} from 'react-native-reanimated'
import {useSafeAreaFrame} from 'react-native-safe-area-context' import {useSafeAreaFrame} from 'react-native-safe-area-context'
import {Image, ImageStyle} from 'expo-image' import {Image, ImageStyle} from 'expo-image'
@@ -37,7 +32,12 @@ type Props = {
onZoom: (scaled: boolean) => void onZoom: (scaled: boolean) => void
isScrollViewBeingDragged: boolean isScrollViewBeingDragged: boolean
showControls: boolean showControls: boolean
safeAreaRef: AnimatedRef<View> measureSafeArea: () => {
x: number
y: number
width: number
height: number
}
imageAspect: number | undefined imageAspect: number | undefined
imageDimensions: ImageDimensions | undefined imageDimensions: ImageDimensions | undefined
imageStyle: StyleProp<ImageStyle> imageStyle: StyleProp<ImageStyle>
@@ -49,7 +49,7 @@ const ImageItem = ({
onTap, onTap,
onZoom, onZoom,
showControls, showControls,
safeAreaRef, measureSafeArea,
imageAspect, imageAspect,
imageDimensions, imageDimensions,
imageStyle, imageStyle,
@@ -103,10 +103,7 @@ const ImageItem = ({
.numberOfTaps(2) .numberOfTaps(2)
.onEnd(e => { .onEnd(e => {
'worklet' 'worklet'
const screenSize = measure(safeAreaRef) const screenSize = measureSafeArea()
if (!screenSize) {
return
}
const {absoluteX, absoluteY} = e const {absoluteX, absoluteY} = e
let nextZoomRect = { let nextZoomRect = {
x: 0, x: 0,
@@ -3,7 +3,6 @@
import React from 'react' import React from 'react'
import {ImageStyle, StyleProp, View} from 'react-native' import {ImageStyle, StyleProp, View} from 'react-native'
import {PanGesture} from 'react-native-gesture-handler' import {PanGesture} from 'react-native-gesture-handler'
import {AnimatedRef} from 'react-native-reanimated'
import {Dimensions as ImageDimensions, ImageSource} from '../../@types' import {Dimensions as ImageDimensions, ImageSource} from '../../@types'
@@ -14,7 +13,12 @@ type Props = {
onZoom: (scaled: boolean) => void onZoom: (scaled: boolean) => void
isScrollViewBeingDragged: boolean isScrollViewBeingDragged: boolean
showControls: boolean showControls: boolean
safeAreaRef: AnimatedRef<View> measureSafeArea: () => {
x: number
y: number
width: number
height: number
}
imageAspect: number | undefined imageAspect: number | undefined
imageDimensions: ImageDimensions | undefined imageDimensions: ImageDimensions | undefined
imageStyle: StyleProp<ImageStyle> imageStyle: StyleProp<ImageStyle>
+35 -6
View File
@@ -33,7 +33,12 @@ import Animated, {
withDecay, withDecay,
withSpring, withSpring,
} from 'react-native-reanimated' } from 'react-native-reanimated'
import {Edge, SafeAreaView} from 'react-native-safe-area-context' import {
Edge,
SafeAreaView,
useSafeAreaFrame,
useSafeAreaInsets,
} from 'react-native-safe-area-context'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {Trans} from '@lingui/macro' import {Trans} from '@lingui/macro'
@@ -49,6 +54,8 @@ import {ImageSource} from './@types'
import ImageDefaultHeader from './components/ImageDefaultHeader' import ImageDefaultHeader from './components/ImageDefaultHeader'
import ImageItem from './components/ImageItem/ImageItem' import ImageItem from './components/ImageItem/ImageItem'
type Rect = {x: number; y: number; width: number; height: number}
const PIXEL_RATIO = PixelRatio.get() const PIXEL_RATIO = PixelRatio.get()
const SLOW_SPRING = {stiffness: 120} const SLOW_SPRING = {stiffness: 120}
const FAST_SPRING = {stiffness: 700} const FAST_SPRING = {stiffness: 700}
@@ -340,13 +347,35 @@ function LightboxImage({
knownDimensions: imageSrc.dimensions, knownDimensions: imageSrc.dimensions,
}) })
const safeFrameDelayedForJSThreadOnly = useSafeAreaFrame()
const safeInsetsDelayedForJSThreadOnly = useSafeAreaInsets()
const measureSafeArea = React.useCallback(() => {
'worklet'
let safeArea: Rect | null = measure(safeAreaRef)
if (!safeArea) {
if (_WORKLET) {
console.error('Expected to always be able to measure safe area.')
}
const frame = safeFrameDelayedForJSThreadOnly
const insets = safeInsetsDelayedForJSThreadOnly
safeArea = {
x: frame.x + insets.left,
y: frame.y + insets.top,
width: frame.width - insets.left - insets.right,
height: frame.height - insets.top - insets.bottom,
}
}
return safeArea
}, [
safeFrameDelayedForJSThreadOnly,
safeInsetsDelayedForJSThreadOnly,
safeAreaRef,
])
const {thumbRect, dimensions} = imageSrc const {thumbRect, dimensions} = imageSrc
const interpolation = useDerivedValue(() => { const interpolation = useDerivedValue(() => {
'worklet' 'worklet'
const safeArea = measure(safeAreaRef) const safeArea = measureSafeArea()
if (!safeArea) {
return {transform: [], width: 0, height: 0}
}
const finalWidth = safeArea.width const finalWidth = safeArea.width
const finalHeight = imageAspect ? safeArea.width / imageAspect : undefined const finalHeight = imageAspect ? safeArea.width / imageAspect : undefined
if (isActive && thumbRect && dimensions && openProgress.value < 1) { if (isActive && thumbRect && dimensions && openProgress.value < 1) {
@@ -431,7 +460,7 @@ function LightboxImage({
onRequestClose={onRequestClose} onRequestClose={onRequestClose}
isScrollViewBeingDragged={isScrollViewBeingDragged} isScrollViewBeingDragged={isScrollViewBeingDragged}
showControls={showControls} showControls={showControls}
safeAreaRef={safeAreaRef} measureSafeArea={measureSafeArea}
imageAspect={imageAspect} imageAspect={imageAspect}
imageDimensions={imageDimensions} imageDimensions={imageDimensions}
imageStyle={imageStyle} imageStyle={imageStyle}