Skip to content

Instantly share code, notes, and snippets.

@AlexeyTsutsoev
Created March 16, 2023 08:07
Show Gist options
  • Save AlexeyTsutsoev/bacd41e038aab64bb93c95a6486392dc to your computer and use it in GitHub Desktop.
Save AlexeyTsutsoev/bacd41e038aab64bb93c95a6486392dc to your computer and use it in GitHub Desktop.
Animated Image Example
import React, { useCallback, useState, FC } from 'react';
import FastImage, { Source } from 'react-native-fast-image';
import Animated, {
Extrapolate,
interpolate,
SharedValue,
useAnimatedStyle,
} from 'react-native-reanimated';
import { styled } from '@shared/ui/theme';
import { ImageSkeleton } from './skeleton';
const ImageContainer = styled(Animated.View)<{ imageHeight: number }>`
width: 100%;
height: ${({ imageHeight }) => imageHeight}px;
`;
const StyledImage = styled(FastImage)<{ isLoading: boolean }>`
width: 100%;
height: 100%;
display: ${({ isLoading }) => (isLoading ? 'none' : 'flex')};
`;
type Props = {
scaleValue: SharedValue<number>;
imageSource: Source;
imageHeight: number;
};
export const AnimatedScaleImage: FC<Props> = ({
scaleValue,
imageHeight,
imageSource,
}) => {
const [isLoadImage, setLoadImage] = useState(false);
const onLoadStart = useCallback(() => {
setLoadImage(true);
}, [setLoadImage]);
const onLoaded = useCallback(() => {
setLoadImage(false);
}, [setLoadImage]);
const animatedImageStyled = useAnimatedStyle(() => {
return {
transform: [
{
scale: interpolate(
scaleValue.value,
[-imageHeight, 0],
[3, 1],
Extrapolate.CLAMP,
),
},
{
scaleY: interpolate(
scaleValue.value,
[-imageHeight, 0],
[1.1, 1],
Extrapolate.CLAMP,
),
},
{ translateY: -(scaleValue.value / 5) },
],
opacity: interpolate(scaleValue.value, [0, imageHeight], [1, 0]),
};
});
return (
<ImageContainer imageHeight={imageHeight} style={animatedImageStyled}>
<StyledImage
isLoading={isLoadImage}
resizeMode="cover"
source={imageSource}
onLoadStart={onLoadStart}
onLoad={onLoaded}
/>
{isLoadImage && <ImageSkeleton />}
</ImageContainer>
);
};
import React from 'react';
import { SkeletonItem, SkeletonTemplate } from '../../skeleton-template';
export const ImageSkeleton = () => {
return (
<SkeletonTemplate>
<SkeletonItem width="100%" height="100%" />
</SkeletonTemplate>
);
};
import React from 'react';
import { ComponentProps } from 'react';
import SkeletonPlaceholder from 'react-native-skeleton-placeholder';
import { useTheme } from '@shared/lib/hooks';
type Props = ComponentProps<typeof SkeletonPlaceholder>;
export const SkeletonTemplate = ({ children, ...rest }: Props) => {
const theme = useTheme();
return (
<SkeletonPlaceholder
borderRadius={6}
highlightColor={theme.palette.content.accent}
{...rest}>
{children}
</SkeletonPlaceholder>
);
};
export const SkeletonItem = SkeletonPlaceholder.Item;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment