/ components / ShimmerEffect.tsx
ShimmerEffect.tsx
1 import React, { useEffect, useRef } from 'react'; 2 import { Animated, View, ViewStyle } from 'react-native'; 3 import { LinearGradient } from 'expo-linear-gradient'; 4 import { useTheme } from '@/constants/ThemeContext'; 5 // import { Colors } from '@/constants/Colors'; 6 7 import { DimensionValue } from 'react-native'; 8 9 interface ShimmerEffectProps { 10 width?: DimensionValue; 11 height?: number; 12 borderRadius?: number; 13 style?: ViewStyle; 14 } 15 16 export const ShimmerEffect: React.FC<ShimmerEffectProps> = ({ 17 width = 100, 18 height = 20, 19 borderRadius = 4, 20 style, 21 }) => { 22 const { actualTheme } = useTheme(); 23 const shimmerAnimation = useRef(new Animated.Value(0)).current; 24 25 useEffect(() => { 26 const startShimmer = () => { 27 shimmerAnimation.setValue(0); 28 Animated.loop( 29 Animated.timing(shimmerAnimation, { 30 toValue: 1, 31 duration: 1500, 32 useNativeDriver: true, 33 }) 34 ).start(); 35 }; 36 37 startShimmer(); 38 }, [shimmerAnimation]); 39 40 const translateX = shimmerAnimation.interpolate({ 41 inputRange: [0, 1], 42 outputRange: [-300, 300], 43 }); 44 45 const baseColor = actualTheme === 'dark' ? '#2C2C2E' : '#F2F2F7'; 46 const highlightColor = actualTheme === 'dark' ? '#3C3C3E' : '#FFFFFF'; 47 48 return ( 49 <View 50 style={[ 51 { 52 width, 53 height, 54 borderRadius, 55 backgroundColor: baseColor, 56 overflow: 'hidden', 57 }, 58 style, 59 ]} 60 > 61 <Animated.View 62 style={{ 63 width: '100%', 64 height: '100%', 65 transform: [{ translateX }], 66 }} 67 > 68 <LinearGradient 69 colors={[baseColor, highlightColor, baseColor]} 70 start={{ x: 0, y: 0 }} 71 end={{ x: 1, y: 0 }} 72 style={{ 73 width: 300, 74 height: '100%', 75 }} 76 /> 77 </Animated.View> 78 </View> 79 ); 80 }; 81 82 // Convenience components for common use cases 83 export const ShimmerCard: React.FC<{ style?: ViewStyle }> = ({ style }) => ( 84 <View style={style}> 85 <ShimmerEffect width="100%" height={200} borderRadius={12} /> 86 <ShimmerEffect width="80%" height={16} style={{ marginTop: 8 }} /> 87 <ShimmerEffect width="60%" height={12} style={{ marginTop: 4 }} /> 88 </View> 89 ); 90 91 export const ShimmerText: React.FC<{ 92 lines?: number; 93 width?: DimensionValue; 94 style?: ViewStyle; 95 }> = ({ lines = 3, width = '100%' as DimensionValue, style }) => ( 96 <View style={style}> 97 {Array.from({ length: lines }).map((_, index) => ( 98 <ShimmerEffect 99 key={index} 100 width={index === lines - 1 ? ('70%' as DimensionValue) : width} 101 height={16} 102 style={{ marginBottom: index < lines - 1 ? 8 : 0 }} 103 /> 104 ))} 105 </View> 106 );