Kurs React Native · Moduł 6: Zdjęcia, kamera i dźwięk
expo-image - Optymalne wyświetlanie obrazów
W tej lekcji6
Witaj w Kryształowej Galerii! Nauczysz się obsługiwać multimedia w aplikacjach mobilnych.
Instalacja expo-image
npx expo install expo-imagePodstawowe użycie
import { Image } from 'expo-image';
import { StyleSheet, View } from 'react-native';
function ImageGallery() {
return (
<View style={styles.container}>
{/* Obraz z URL */}
<Image
source={{ uri: 'https://atlantyda.app/images/crystal.jpg' }}
style={styles.image}
contentFit="cover"
transition={300}
/>
{/* Obraz lokalny */}
<Image
source={require('@/assets/images/pearl.png')}
style={styles.image}
contentFit="contain"
/>
{/* Z placeholderem i blur */}
<Image
source={{ uri: 'https://atlantyda.app/images/large.jpg' }}
placeholder={blurhash}
style={styles.image}
contentFit="cover"
transition={500}
/>
</View>
);
}
const blurhash = 'L6PZfSi_.AyE_3t7t7R**0o#DgR4';
const styles = StyleSheet.create({
container: {
flex: 1,
},
image: {
width: '100%',
height: 200,
borderRadius: 12,
},
});contentFit (dawniej resizeMode)
// Różne tryby dopasowania
<Image source={source} contentFit="cover" /> // Wypełnia, może przycinać
<Image source={source} contentFit="contain" /> // Cały widoczny, może być padding
<Image source={source} contentFit="fill" /> // Rozciąga do wymiarów
<Image source={source} contentFit="none" /> // Oryginalne wymiary
<Image source={source} contentFit="scale-down" /> // contain lub none (mniejszy)Blurhash i placeholder
import { Image } from 'expo-image';
// Blurhash - kompaktowy placeholder
const blurhash = 'L6PZfSi_.AyE_3t7t7R**0o#DgR4';
function OptimizedImage() {
return (
<Image
source={{ uri: 'https://example.com/image.jpg' }}
placeholder={blurhash}
placeholderContentFit="cover"
style={styles.image}
transition={500}
/>
);
}Cachowanie
import { Image } from 'expo-image';
// Ustawienia cache
<Image
source={{ uri: imageUrl }}
cachePolicy="memory-disk" // memory, disk, memory-disk, none
style={styles.image}
/>
// Prefetching
import { Image } from 'expo-image';
async function preloadImages() {
const urls = [
'https://example.com/image1.jpg',
'https://example.com/image2.jpg',
];
await Promise.all(urls.map((url) => Image.prefetch(url)));
}Lista obrazów z FlatList
interface ImageItem {
id: string;
uri: string;
title: string;
}
function ImageList() {
const [images, setImages] = useState<ImageItem[]>([]);
return (
<FlatList
data={images}
numColumns={2}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<Pressable style={styles.imageCard}>
<Image
source={{ uri: item.uri }}
style={styles.gridImage}
contentFit="cover"
transition={200}
/>
<Text style={styles.imageTitle}>{item.title}</Text>
</Pressable>
)}
/>
);
}expo-image jest znacznie wydajniejszy niż standardowy Image z React Native!
Kod do tej lekcji: App.tsx
import React, { useState } from 'react';
import { View, Text, FlatList, Pressable, StyleSheet } from 'react-native';
import { Image } from 'expo-image';
interface ImageItem {
id: string;
uri: string;
title: string;
}
export default function App() {
const [images] = useState<ImageItem[]>([
{ id: '1', uri: 'https://picsum.photos/200?1', title: 'Kryształ' },
{ id: '2', uri: 'https://picsum.photos/200?2', title: 'Perła' },
]);
return (
<FlatList
data={images}
numColumns={2}
keyExtractor={(item) => item.id}
contentContainerStyle={styles.grid}
renderItem={({ item }) => (
<Pressable style={styles.card}>
{/* TODO: dodaj <Image> z expo-image, który:
- ma source={{ uri: item.uri }}
- korzysta ze stylu styles.image
- ma contentFit="cover"
- ma transition={200} dla płynnego pojawiania się */}
<Text style={styles.title}>{item.title}</Text>
</Pressable>
)}
/>
);
}
const styles = StyleSheet.create({
grid: { padding: 8 },
card: { flex: 1, margin: 4 },
image: {
width: '100%',
height: 150,
borderRadius: 12,
},
title: {
color: '#aed6f1',
textAlign: 'center',
marginTop: 6,
},
});Hasła z dokumentacji w tej lekcji
Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Która wartość contentFit wypełnia kontener, potencjalnie przycinając obraz?
2. Do czego służy blurhash w expo-image?
Zadania praktyczne w grze
- Układanie w poziomie
Ułóż prefetching obrazu:
- Edytor kodu
Uzupełnij kod FlatList z expo-image.