Animate cropped borders

This commit is contained in:
Dan Abramov
2024-11-03 03:41:07 +00:00
parent caeb86a368
commit 8e96154a4d
4 changed files with 141 additions and 62 deletions
@@ -1,5 +1,10 @@
import React, {useState} from 'react'
import {ActivityIndicator, Dimensions, StyleSheet} from 'react-native'
import {
ActivityIndicator,
Dimensions,
StyleProp,
StyleSheet,
} from 'react-native'
import {
Gesture,
GestureDetector,
@@ -13,7 +18,7 @@ import Animated, {
useSharedValue,
withSpring,
} from 'react-native-reanimated'
import {Image} from 'expo-image'
import {Image, ImageStyle} from 'expo-image'
import {useImageDimensions} from '#/lib/media/image-sizes'
import type {Dimensions as ImageDimensions, ImageSource} from '../../@types'
@@ -27,6 +32,8 @@ import {
TransformMatrix,
} from '../../transforms'
const AnimatedImage = Animated.createAnimatedComponent(Image)
const windowDim = Dimensions.get('window')
const screenDim = Dimensions.get('screen')
const statusBarHeight = windowDim.height - screenDim.height
@@ -47,13 +54,16 @@ type Props = {
isPagingAndroid: boolean
showControls: boolean
dismissSwipePan: PanGesture
imageStyle: StyleProp<ImageStyle>
}
const ImageItem = ({
imageSrc,
onTap,
onZoom,
isPagingAndroid,
dismissSwipePan,
imageStyle,
}: Props) => {
const [isScaled, setIsScaled] = useState(false)
const [imageAspect, imageDimensions] = useImageDimensions({
@@ -307,21 +317,24 @@ const ImageItem = ({
renderToHardwareTextureAndroid
style={[styles.container, animatedStyle, {}]}>
<ActivityIndicator size="small" color="#FFF" style={styles.loading} />
<Image
contentFit="contain"
<AnimatedImage
contentFit="cover"
source={{uri: imageSrc.uri}}
placeholderContentFit="contain"
placeholderContentFit="cover"
placeholder={{uri: imageSrc.thumbUri}}
style={{
width: SCREEN.width,
height: imageAspect ? SCREEN.width / imageAspect : undefined,
borderRadius:
imageSrc.type === 'circle-avi'
? SCREEN.width / 2
: imageSrc.type === 'rect-avi'
? 20
: 0,
}}
style={[
{
width: SCREEN.width,
height: imageAspect ? SCREEN.width / imageAspect : undefined,
borderRadius:
imageSrc.type === 'circle-avi'
? SCREEN.width / 2
: imageSrc.type === 'rect-avi'
? 20
: 0,
},
imageStyle,
]}
accessibilityLabel={imageSrc.alt}
accessibilityHint=""
accessibilityIgnoresInvertColors
@@ -7,19 +7,26 @@
*/
import React, {useState} from 'react'
import {ActivityIndicator, Dimensions, StyleSheet} from 'react-native'
import {
ActivityIndicator,
Dimensions,
StyleProp,
StyleSheet,
} from 'react-native'
import {
Gesture,
GestureDetector,
PanGesture,
} from 'react-native-gesture-handler'
import Animated, {runOnJS, useAnimatedRef} from 'react-native-reanimated'
import {Image} from 'expo-image'
import {Image, ImageStyle} from 'expo-image'
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
import {useImageDimensions} from '#/lib/media/image-sizes'
import {ImageSource} from '../../@types'
const AnimatedImage = Animated.createAnimatedComponent(Image)
const SCREEN = Dimensions.get('screen')
const MAX_ORIGINAL_IMAGE_ZOOM = 2
const MIN_DOUBLE_TAP_SCALE = 2
@@ -32,6 +39,7 @@ type Props = {
isPagingAndroid: boolean // Not available on iOS
showControls: boolean
dismissSwipePan: PanGesture | null
imageStyle: StyleProp<ImageStyle>
}
const ImageItem = ({
@@ -40,6 +48,7 @@ const ImageItem = ({
onZoom,
showControls,
dismissSwipePan,
imageStyle,
}: Props) => {
const scrollViewRef = useAnimatedRef<Animated.ScrollView>()
@@ -145,21 +154,24 @@ const ImageItem = ({
bounces={scaled}
centerContent>
<ActivityIndicator size="small" color="#FFF" style={styles.loading} />
<Image
contentFit="contain"
<AnimatedImage
contentFit="cover"
source={{uri: imageSrc.uri}}
placeholderContentFit="contain"
placeholderContentFit="cover"
placeholder={{uri: imageSrc.thumbUri}}
style={{
width: SCREEN.width,
height: imageAspect ? SCREEN.width / imageAspect : undefined,
borderRadius:
imageSrc.type === 'circle-avi'
? SCREEN.width / 2
: imageSrc.type === 'rect-avi'
? 20
: 0,
}}
style={[
{
width: SCREEN.width,
height: imageAspect ? SCREEN.width / imageAspect : undefined,
borderRadius:
imageSrc.type === 'circle-avi'
? SCREEN.width / 2
: imageSrc.type === 'rect-avi'
? 20
: 0,
},
imageStyle,
]}
accessibilityLabel={imageSrc.alt}
accessibilityHint=""
enableLiveTextInteraction={showControls && !scaled}
@@ -1,8 +1,9 @@
// default implementation fallback for web
import React from 'react'
import {View} from 'react-native'
import {StyleProp,View} from 'react-native'
import {PanGesture} from 'react-native-gesture-handler'
import {ImageStyle} from 'expo-image'
import {ImageSource} from '../../@types'
@@ -14,6 +15,7 @@ type Props = {
isPagingAndroid: boolean
showControls: boolean
dismissSwipePan: PanGesture | null
imageStyle: StyleProp<ImageStyle>
}
const ImageItem = (_props: Props) => {