Sélecteur d'images
Utilisation d'expo-image-picker pour sélectionner des images de la galerie, les compresser et les uploader vers votre backend.
Sélecteur d'images
expo-image-picker permet aux utilisateurs de sélectionner des photos de leur galerie ou d'en prendre de nouvelles. ScaleRocket Mobile l'utilise pour les avatars, les images de posts et les pièces jointes.
Installation
npx expo install expo-image-pickerAjoutez les descriptions de permission dans app.json :
{
"expo": {
"ios": {
"infoPlist": {
"NSPhotoLibraryUsageDescription": "We access your photos to let you upload a profile picture"
}
}
}
}Sélectionner une image
import * as ImagePicker from "expo-image-picker";
async function pickImage() {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [1, 1],
quality: 0.8,
});
if (!result.canceled) {
const image = result.assets[0];
console.log("Selected:", image.uri);
return image;
}
}| Option | Valeur | Objectif |
|---|---|---|
mediaTypes | Images, Videos, All | Filtrer le type de média |
allowsEditing | true | Afficher l'UI de recadrage/redimensionnement |
aspect | [1, 1] | Ratio de recadrage (iOS uniquement) |
quality | 0.0 - 1.0 | Compression de l'image |
Prendre une photo
Utilisez launchCameraAsync pour ouvrir la caméra directement :
async function takePhoto() {
const permission = await ImagePicker.requestCameraPermissionsAsync();
if (!permission.granted) {
Alert.alert("Permission required", "Camera access is needed to take photos");
return;
}
const result = await ImagePicker.launchCameraAsync({
allowsEditing: true,
aspect: [1, 1],
quality: 0.8,
});
if (!result.canceled) {
return result.assets[0];
}
}Compression d'image
Compressez les images avant l'upload pour réduire la bande passante et le stockage :
import { manipulateAsync, SaveFormat } from "expo-image-manipulator";
async function compressImage(uri: string) {
const result = await manipulateAsync(
uri,
[{ resize: { width: 800 } }],
{ compress: 0.7, format: SaveFormat.JPEG }
);
return result.uri;
}npx expo install expo-image-manipulatorUpload vers le backend
Upload vers Supabase Storage :
import { supabase } from "@/lib/supabase";
async function uploadImage(uri: string, userId: string) {
const compressedUri = await compressImage(uri);
const fileName = `${userId}/avatar-${Date.now()}.jpg`;
const formData = new FormData();
formData.append("file", {
uri: compressedUri,
name: "avatar.jpg",
type: "image/jpeg",
} as any);
const { data, error } = await supabase.storage
.from("avatars")
.upload(fileName, formData, { upsert: true });
if (error) throw error;
const { data: urlData } = supabase.storage
.from("avatars")
.getPublicUrl(fileName);
return urlData.publicUrl;
}Upload vers Convex File Storage :
import { useMutation } from "convex/react";
import { api } from "@/convex/_generated/api";
async function uploadImage(uri: string) {
const compressedUri = await compressImage(uri);
// Obtenir l'URL d'upload
const uploadUrl = await generateUploadUrl();
// Uploader le fichier
const response = await fetch(compressedUri);
const blob = await response.blob();
const result = await fetch(uploadUrl, {
method: "POST",
body: blob,
headers: { "Content-Type": "image/jpeg" },
});
const { storageId } = await result.json();
return storageId;
}Composant complet d'upload d'avatar
function AvatarUpload({ user }: { user: User }) {
const [uploading, setUploading] = useState(false);
const [avatarUri, setAvatarUri] = useState(user.avatarUrl);
const handleUpload = async () => {
const image = await pickImage();
if (!image) return;
setUploading(true);
try {
const url = await uploadImage(image.uri, user.id);
setAvatarUri(url);
} catch (error) {
Alert.alert("Upload Failed", "Could not upload image. Try again.");
} finally {
setUploading(false);
}
};
return (
<TouchableOpacity onPress={handleUpload} disabled={uploading}>
<Avatar source={avatarUri ? { uri: avatarUri } : undefined} name={user.name} size="lg" />
{uploading && <ActivityIndicator style={styles.overlay} />}
</TouchableOpacity>
);
}Sélection multiple d'images
Sélectionnez plusieurs images à la fois :
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsMultipleSelection: true,
selectionLimit: 5,
quality: 0.8,
});
if (!result.canceled) {
const images = result.assets; // Tableau d'images sélectionnées
}Notes
allowsEditingne supporte que la sélection d'une seule image- Sur iOS, le ratio
aspectn'est appliqué que quandallowsEditingest true - Les grandes images doivent toujours être compressées avant l'upload
- Le sélecteur d'images fonctionne dans Expo Go (contrairement à la caméra)