281 lines
6.3 KiB
Markdown
281 lines
6.3 KiB
Markdown
# Asset Management
|
|
|
|
## Folder Structure
|
|
|
|
```
|
|
src/assets/
|
|
├── images/
|
|
│ ├── logo.png
|
|
│ ├── logo@2x.png
|
|
│ └── logo@3x.png
|
|
├── icons/
|
|
│ └── index.ts
|
|
└── fonts/
|
|
├── Montserrat-Regular.ttf
|
|
└── Montserrat-Bold.ttf
|
|
```
|
|
|
|
## Image Management
|
|
|
|
**Create image index file:**
|
|
```typescript
|
|
// src/assets/images/index.ts
|
|
export const Images = {
|
|
logo: require('./logo.png'),
|
|
splash: require('./splash.png'),
|
|
placeholder: require('./placeholder.png'),
|
|
// Add more images here
|
|
};
|
|
```
|
|
|
|
**Usage in components:**
|
|
```typescript
|
|
import {Images} from '@assets/images';
|
|
import {Image} from 'react-native';
|
|
|
|
const MyComponent = () => (
|
|
<Image source={Images.logo} style={{width: 100, height: 100}} />
|
|
);
|
|
```
|
|
|
|
## Icon Management
|
|
|
|
**Install react-native-vector-icons:**
|
|
```bash
|
|
yarn add react-native-vector-icons
|
|
yarn add -D @types/react-native-vector-icons
|
|
|
|
# iOS setup
|
|
cd ios && pod install
|
|
```
|
|
|
|
**Create icon component:**
|
|
```typescript
|
|
// src/components/common/Icon/Icon.tsx
|
|
import React from 'react';
|
|
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
|
import FontAwesome from 'react-native-vector-icons/FontAwesome';
|
|
|
|
type IconFamily = 'MaterialIcons' | 'Ionicons' | 'FontAwesome';
|
|
|
|
interface IconProps {
|
|
name: string;
|
|
size?: number;
|
|
color?: string;
|
|
family?: IconFamily;
|
|
}
|
|
|
|
const IconComponents = {
|
|
MaterialIcons,
|
|
Ionicons,
|
|
FontAwesome,
|
|
};
|
|
|
|
export const Icon: React.FC<IconProps> = ({
|
|
name,
|
|
size = 24,
|
|
color = '#000',
|
|
family = 'MaterialIcons',
|
|
}) => {
|
|
const IconComponent = IconComponents[family];
|
|
return <IconComponent name={name} size={size} color={color} />;
|
|
};
|
|
```
|
|
|
|
## SVG Icons
|
|
|
|
**Install react-native-svg:**
|
|
```bash
|
|
yarn add react-native-svg
|
|
yarn add -D @types/react-native-svg
|
|
|
|
# iOS setup
|
|
cd ios && pod install
|
|
```
|
|
|
|
**Create SVG icon component:**
|
|
```typescript
|
|
// src/components/common/SvgIcon/SvgIcon.tsx
|
|
import React from 'react';
|
|
import Svg, {Path, Circle, Rect} from 'react-native-svg';
|
|
|
|
interface SvgIconProps {
|
|
name: string;
|
|
size?: number;
|
|
color?: string;
|
|
}
|
|
|
|
const iconPaths = {
|
|
home: 'M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z',
|
|
user: 'M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z',
|
|
// Add more icon paths
|
|
};
|
|
|
|
export const SvgIcon: React.FC<SvgIconProps> = ({
|
|
name,
|
|
size = 24,
|
|
color = '#000',
|
|
}) => {
|
|
const path = iconPaths[name as keyof typeof iconPaths];
|
|
|
|
if (!path) {
|
|
console.warn(`Icon "${name}" not found`);
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<Svg width={size} height={size} viewBox="0 0 24 24" fill={color}>
|
|
<Path d={path} />
|
|
</Svg>
|
|
);
|
|
};
|
|
```
|
|
|
|
## Image Optimization
|
|
|
|
**Install react-native-fast-image:**
|
|
```bash
|
|
yarn add react-native-fast-image
|
|
|
|
# iOS setup
|
|
cd ios && pod install
|
|
```
|
|
|
|
**Optimized image component:**
|
|
```typescript
|
|
// src/components/common/OptimizedImage/OptimizedImage.tsx
|
|
import React from 'react';
|
|
import FastImage, {FastImageProps} from 'react-native-fast-image';
|
|
import {StyleSheet, View, ActivityIndicator} from 'react-native';
|
|
|
|
interface OptimizedImageProps extends FastImageProps {
|
|
showLoader?: boolean;
|
|
loaderColor?: string;
|
|
}
|
|
|
|
export const OptimizedImage: React.FC<OptimizedImageProps> = ({
|
|
showLoader = true,
|
|
loaderColor = '#007AFF',
|
|
style,
|
|
...props
|
|
}) => {
|
|
const [loading, setLoading] = React.useState(true);
|
|
|
|
return (
|
|
<View style={style}>
|
|
<FastImage
|
|
{...props}
|
|
style={[StyleSheet.absoluteFillObject, style]}
|
|
onLoadStart={() => setLoading(true)}
|
|
onLoadEnd={() => setLoading(false)}
|
|
resizeMode={FastImage.resizeMode.cover}
|
|
/>
|
|
{loading && showLoader && (
|
|
<View style={styles.loader}>
|
|
<ActivityIndicator color={loaderColor} />
|
|
</View>
|
|
)}
|
|
</View>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
loader: {
|
|
...StyleSheet.absoluteFillObject,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
backgroundColor: 'rgba(0, 0, 0, 0.1)',
|
|
},
|
|
});
|
|
```
|
|
|
|
## Asset Preloading
|
|
|
|
```typescript
|
|
// src/utils/assetPreloader.ts
|
|
import {Image} from 'react-native';
|
|
import {Images} from '@assets/images';
|
|
|
|
export const preloadImages = async (): Promise<void> => {
|
|
const imagePromises = Object.values(Images).map(image => {
|
|
return new Promise<void>((resolve, reject) => {
|
|
Image.prefetch(Image.resolveAssetSource(image).uri)
|
|
.then(() => resolve())
|
|
.catch(reject);
|
|
});
|
|
});
|
|
|
|
try {
|
|
await Promise.all(imagePromises);
|
|
console.log('All images preloaded successfully');
|
|
} catch (error) {
|
|
console.error('Error preloading images:', error);
|
|
}
|
|
};
|
|
```
|
|
|
|
## Image Caching Strategy
|
|
|
|
```typescript
|
|
// src/utils/imageCache.ts
|
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
import RNFS from 'react-native-fs';
|
|
|
|
const CACHE_DIR = `${RNFS.CachesDirectoryPath}/images`;
|
|
const CACHE_KEY_PREFIX = 'image_cache_';
|
|
|
|
export class ImageCache {
|
|
static async getCachedImagePath(url: string): Promise<string | null> {
|
|
try {
|
|
const cacheKey = `${CACHE_KEY_PREFIX}${this.hashUrl(url)}`;
|
|
const cachedPath = await AsyncStorage.getItem(cacheKey);
|
|
|
|
if (cachedPath && await RNFS.exists(cachedPath)) {
|
|
return cachedPath;
|
|
}
|
|
|
|
return null;
|
|
} catch (error) {
|
|
console.error('Error getting cached image:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static async cacheImage(url: string): Promise<string> {
|
|
try {
|
|
const fileName = this.hashUrl(url);
|
|
const filePath = `${CACHE_DIR}/${fileName}`;
|
|
const cacheKey = `${CACHE_KEY_PREFIX}${fileName}`;
|
|
|
|
// Ensure cache directory exists
|
|
await RNFS.mkdir(CACHE_DIR);
|
|
|
|
// Download and cache the image
|
|
await RNFS.downloadFile({
|
|
fromUrl: url,
|
|
toFile: filePath,
|
|
}).promise;
|
|
|
|
// Store the path in AsyncStorage
|
|
await AsyncStorage.setItem(cacheKey, filePath);
|
|
|
|
return filePath;
|
|
} catch (error) {
|
|
console.error('Error caching image:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
private static hashUrl(url: string): string {
|
|
// Simple hash function for URL
|
|
let hash = 0;
|
|
for (let i = 0; i < url.length; i++) {
|
|
const char = url.charCodeAt(i);
|
|
hash = ((hash << 5) - hash) + char;
|
|
hash = hash & hash; // Convert to 32-bit integer
|
|
}
|
|
return Math.abs(hash).toString();
|
|
}
|
|
}
|
|
``` |