Animate crop
This commit is contained in:
@@ -20,8 +20,6 @@ import Animated, {
|
|||||||
} from 'react-native-reanimated'
|
} from 'react-native-reanimated'
|
||||||
import {Image, ImageStyle} from 'expo-image'
|
import {Image, ImageStyle} from 'expo-image'
|
||||||
|
|
||||||
const AnimatedImage = Animated.createAnimatedComponent(Image)
|
|
||||||
|
|
||||||
import {useImageDimensions} from '#/lib/media/image-sizes'
|
import {useImageDimensions} from '#/lib/media/image-sizes'
|
||||||
import type {Dimensions as ImageDimensions, ImageSource} from '../../@types'
|
import type {Dimensions as ImageDimensions, ImageSource} from '../../@types'
|
||||||
import {
|
import {
|
||||||
@@ -308,10 +306,10 @@ const ImageItem = ({
|
|||||||
style={[styles.container, animatedContainerStyle, {}]}>
|
style={[styles.container, animatedContainerStyle, {}]}>
|
||||||
<Animated.View style={animatedStyle}>
|
<Animated.View style={animatedStyle}>
|
||||||
<ActivityIndicator size="small" color="#FFF" style={styles.loading} />
|
<ActivityIndicator size="small" color="#FFF" style={styles.loading} />
|
||||||
<AnimatedImage
|
<Image
|
||||||
contentFit="contain"
|
contentFit="cover"
|
||||||
source={{uri: imageSrc.uri}}
|
source={{uri: imageSrc.uri}}
|
||||||
placeholderContentFit="contain"
|
placeholderContentFit="cover"
|
||||||
placeholder={{uri: imageSrc.thumbUri}}
|
placeholder={{uri: imageSrc.thumbUri}}
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIX
|
|||||||
import {useImageDimensions} from '#/lib/media/image-sizes'
|
import {useImageDimensions} from '#/lib/media/image-sizes'
|
||||||
import {ImageSource} from '../../@types'
|
import {ImageSource} from '../../@types'
|
||||||
|
|
||||||
const AnimatedImage = Animated.createAnimatedComponent(Image)
|
|
||||||
|
|
||||||
const SCREEN = Dimensions.get('screen')
|
const SCREEN = Dimensions.get('screen')
|
||||||
const MAX_ORIGINAL_IMAGE_ZOOM = 2
|
const MAX_ORIGINAL_IMAGE_ZOOM = 2
|
||||||
const MIN_DOUBLE_TAP_SCALE = 2
|
const MIN_DOUBLE_TAP_SCALE = 2
|
||||||
@@ -139,7 +137,7 @@ const ImageItem = ({
|
|||||||
centerContent>
|
centerContent>
|
||||||
<Animated.View style={animatedStyle}>
|
<Animated.View style={animatedStyle}>
|
||||||
<ActivityIndicator size="small" color="#FFF" style={styles.loading} />
|
<ActivityIndicator size="small" color="#FFF" style={styles.loading} />
|
||||||
<AnimatedImage
|
<Image
|
||||||
contentFit="cover"
|
contentFit="cover"
|
||||||
source={{uri: imageSrc.uri}}
|
source={{uri: imageSrc.uri}}
|
||||||
placeholderContentFit="cover"
|
placeholderContentFit="cover"
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import React, {useCallback, useMemo, useState} from 'react'
|
|||||||
import {
|
import {
|
||||||
Dimensions,
|
Dimensions,
|
||||||
LayoutAnimation,
|
LayoutAnimation,
|
||||||
|
PixelRatio,
|
||||||
Platform,
|
Platform,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
View,
|
View,
|
||||||
@@ -48,8 +49,8 @@ import ImageDefaultHeader from './components/ImageDefaultHeader'
|
|||||||
import ImageItem from './components/ImageItem/ImageItem'
|
import ImageItem from './components/ImageItem/ImageItem'
|
||||||
|
|
||||||
const SCREEN = Dimensions.get('screen')
|
const SCREEN = Dimensions.get('screen')
|
||||||
|
|
||||||
const SCREEN_HEIGHT = Dimensions.get('window').height
|
const SCREEN_HEIGHT = Dimensions.get('window').height
|
||||||
|
const PIXEL_RATIO = PixelRatio.get()
|
||||||
|
|
||||||
function ImageViewing({
|
function ImageViewing({
|
||||||
lightbox,
|
lightbox,
|
||||||
@@ -339,6 +340,16 @@ function LightboxFooter({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function interpolatePx(
|
||||||
|
px: number,
|
||||||
|
inputRange: readonly number[],
|
||||||
|
outputRange: readonly number[],
|
||||||
|
) {
|
||||||
|
'worklet'
|
||||||
|
const value = interpolate(px, inputRange, outputRange)
|
||||||
|
return Math.round(value * PIXEL_RATIO) / PIXEL_RATIO
|
||||||
|
}
|
||||||
|
|
||||||
function interpolateFromThumbnail(
|
function interpolateFromThumbnail(
|
||||||
progress: number,
|
progress: number,
|
||||||
thumbnailDims: {
|
thumbnailDims: {
|
||||||
@@ -351,37 +362,47 @@ function interpolateFromThumbnail(
|
|||||||
imageDims: {width: number; height: number},
|
imageDims: {width: number; height: number},
|
||||||
) {
|
) {
|
||||||
'worklet'
|
'worklet'
|
||||||
|
const imageAspect = imageDims.width / imageDims.height
|
||||||
|
const thumbAspect = thumbnailDims.width / thumbnailDims.height
|
||||||
|
let uncroppedInitialWidth
|
||||||
|
let uncroppedInitialHeight
|
||||||
|
if (imageAspect > thumbAspect) {
|
||||||
|
uncroppedInitialWidth = thumbnailDims.height * imageAspect
|
||||||
|
uncroppedInitialHeight = thumbnailDims.height
|
||||||
|
} else {
|
||||||
|
uncroppedInitialWidth = thumbnailDims.width
|
||||||
|
uncroppedInitialHeight = thumbnailDims.width / imageAspect
|
||||||
|
}
|
||||||
|
const finalWidth = screenSize.width
|
||||||
|
const finalHeight = screenSize.width / imageAspect
|
||||||
|
const initialScale = Math.min(
|
||||||
|
uncroppedInitialWidth / finalWidth,
|
||||||
|
uncroppedInitialHeight / finalHeight,
|
||||||
|
)
|
||||||
|
|
||||||
|
const croppedFinalWidth = thumbnailDims.width / initialScale
|
||||||
|
const croppedFinalHeight = thumbnailDims.height / initialScale
|
||||||
const screenCenterX = screenSize.width / 2
|
const screenCenterX = screenSize.width / 2
|
||||||
const screenCenterY = screenSize.height / 2
|
const screenCenterY = screenSize.height / 2
|
||||||
const thumbnailCenterX = thumbnailDims.pageX + thumbnailDims.width / 2
|
const thumbnailCenterX = thumbnailDims.pageX + thumbnailDims.width / 2
|
||||||
const thumbnailCenterY = thumbnailDims.pageY + thumbnailDims.height / 2
|
const thumbnailCenterY = thumbnailDims.pageY + thumbnailDims.height / 2
|
||||||
const initialTranslateX = thumbnailCenterX - screenCenterX
|
const initialTranslateX =
|
||||||
|
thumbnailCenterX + (finalWidth - croppedFinalWidth) / 2 - screenCenterX
|
||||||
const initialTranslateY = thumbnailCenterY - screenCenterY
|
const initialTranslateY = thumbnailCenterY - screenCenterY
|
||||||
|
|
||||||
const imageAspect = imageDims.width / imageDims.height
|
|
||||||
const thumbAspect = thumbnailDims.width / thumbnailDims.height
|
|
||||||
const initialWidth =
|
|
||||||
imageAspect > thumbAspect
|
|
||||||
? thumbnailDims.height * imageAspect
|
|
||||||
: thumbnailDims.width
|
|
||||||
const initialHeight =
|
|
||||||
imageAspect > thumbAspect
|
|
||||||
? thumbnailDims.height
|
|
||||||
: thumbnailDims.width / imageAspect
|
|
||||||
const finalWidth = screenSize.width
|
|
||||||
const finalHeight = screenSize.width / imageAspect
|
|
||||||
const initialScale = Math.min(
|
|
||||||
initialWidth / finalWidth,
|
|
||||||
initialHeight / finalHeight,
|
|
||||||
)
|
|
||||||
|
|
||||||
const translateX = interpolate(progress, [0, 1], [initialTranslateX, 0])
|
|
||||||
const translateY = interpolate(progress, [0, 1], [initialTranslateY, 0])
|
|
||||||
const scale = interpolate(progress, [0, 1], [initialScale, 1])
|
const scale = interpolate(progress, [0, 1], [initialScale, 1])
|
||||||
|
const translateX = interpolatePx(progress, [0, 1], [initialTranslateX, 0])
|
||||||
|
const translateY = interpolatePx(progress, [0, 1], [initialTranslateY, 0])
|
||||||
|
const width = interpolatePx(progress, [0, 1], [croppedFinalWidth, finalWidth])
|
||||||
|
const height = interpolatePx(
|
||||||
|
progress,
|
||||||
|
[0, 1],
|
||||||
|
[croppedFinalHeight, finalHeight],
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
transform: [{translateX}, {translateY}, {scale}],
|
transform: [{translateX}, {translateY}, {scale}],
|
||||||
width: finalWidth,
|
width,
|
||||||
height: finalHeight,
|
height,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -507,7 +528,7 @@ function ImageViewingRoot({
|
|||||||
|
|
||||||
function withClampedSpring(value: any) {
|
function withClampedSpring(value: any) {
|
||||||
'worklet'
|
'worklet'
|
||||||
return withSpring(value, {overshootClamping: true, stiffness: 150})
|
return withSpring(value, {overshootClamping: true, stiffness: 120})
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ImageViewingRoot
|
export default ImageViewingRoot
|
||||||
|
|||||||
Reference in New Issue
Block a user