React Native course · Module 6: Photos, camera and audio
expo-image-picker - Selecting Images
In this lesson6
Let users pick images from their gallery or take photos!
Installation
npx expo install expo-image-pickerPermission Configuration (app.json)
{
"expo": {
"plugins": [
[
"expo-image-picker",
{
"photosPermission": "The app requires access to photos",
"cameraPermission": "The app requires access to the camera"
}
]
]
}
}Picking from Gallery
import * as ImagePicker from 'expo-image-picker';
function PhotoSelector() {
const [image, setImage] = useState<string | null>(null);
const pickImage = async () => {
// Check permissions
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== 'granted') {
Alert.alert('Error', 'No gallery permissions');
return;
}
// Open picker
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ['images'],
allowsEditing: true,
aspect: [4, 3],
quality: 0.8,
});
if (!result.canceled && result.assets[0]) {
setImage(result.assets[0].uri);
}
};
return (
<View style={styles.container}>
<Pressable style={styles.button} onPress={pickImage}>
<Text>Pick a photo</Text>
</Pressable>
{image && (
<Image source={{ uri: image }} style={styles.preview} />
)}
</View>
);
}Taking a Photo
const takePhoto = async () => {
const { status } = await ImagePicker.requestCameraPermissionsAsync();
if (status !== 'granted') {
Alert.alert('Error', 'No camera permissions');
return;
}
const result = await ImagePicker.launchCameraAsync({
allowsEditing: true,
aspect: [1, 1],
quality: 0.9,
});
if (!result.canceled && result.assets[0]) {
setImage(result.assets[0].uri);
}
};ImagePicker Options
const result = await ImagePicker.launchImageLibraryAsync({
// Media types
mediaTypes: ['images', 'videos'], // 'images', 'videos', 'livePhotos' (iOS)
// Editing
allowsEditing: true, // Allow cropping
aspect: [16, 9], // Aspect ratio (only with allowsEditing)
// Quality
quality: 1, // 0-1 (1 = highest)
// Multiple images
allowsMultipleSelection: true,
// Base64
base64: false, // Also return as base64
// EXIF
exif: true, // Photo metadata
});
// Result
if (!result.canceled) {
result.assets.forEach((asset) => {
console.log('URI:', asset.uri);
console.log('Width:', asset.width);
console.log('Height:', asset.height);
console.log('Type:', asset.type); // 'image' or 'video'
console.log('File size:', asset.fileSize);
console.log('EXIF:', asset.exif);
});
}Photo Picker Component
interface ImagePickerButtonProps {
onImageSelected: (uri: string) => void;
}
function ImagePickerButton({ onImageSelected }: ImagePickerButtonProps) {
const showOptions = () => {
Alert.alert(
'Add photo',
'Choose source',
[
{ text: 'Camera', onPress: takePhoto },
{ text: 'Gallery', onPress: pickFromGallery },
{ text: 'Cancel', style: 'cancel' },
]
);
};
const takePhoto = async () => {
const { status } = await ImagePicker.requestCameraPermissionsAsync();
if (status !== 'granted') return;
const result = await ImagePicker.launchCameraAsync({
allowsEditing: true,
quality: 0.8,
});
if (!result.canceled) {
onImageSelected(result.assets[0].uri);
}
};
const pickFromGallery = async () => {
const result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
quality: 0.8,
});
if (!result.canceled) {
onImageSelected(result.assets[0].uri);
}
};
return (
<Pressable style={styles.button} onPress={showOptions}>
<Ionicons name="camera" size={24} />
<Text>Add photo</Text>
</Pressable>
);
}expo-image-picker is the simplest way to select photos in Expo!
Code for this lesson: App.tsx
import React, { useState } from 'react';
import { View, Text, Pressable, StyleSheet, Alert } from 'react-native';
import { Image } from 'expo-image';
import * as ImagePicker from 'expo-image-picker';
export default function App() {
const [image, setImage] = useState<string | null>(null);
const pickFromGallery = async () => {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
quality: 0.8,
});
if (!result.canceled) {
setImage(result.assets[0].uri);
}
};
const takePhoto = async () => {
const result = await ImagePicker.launchCameraAsync({
allowsEditing: true,
quality: 0.8,
});
if (!result.canceled) {
setImage(result.assets[0].uri);
}
};
const showOptions = () => {
// TODO: call Alert.alert with title 'Add photo' and three buttons:
// - { text: 'Camera', onPress: takePhoto }
// - { text: 'Gallery', onPress: pickFromGallery }
// - { text: 'Cancel', style: 'cancel' }
};
return (
<View style={styles.container}>
<Pressable style={styles.button} onPress={showOptions}>
<Text style={styles.buttonText}>Add photo</Text>
</Pressable>
{image && <Image source={{ uri: image }} style={styles.preview} />}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
justifyContent: 'center',
backgroundColor: '#1a5276',
},
button: {
backgroundColor: '#2980b9',
padding: 14,
borderRadius: 8,
alignItems: 'center',
},
buttonText: { color: '#fff', fontSize: 16, fontWeight: '600' },
preview: { width: '100%', height: 250, borderRadius: 12, marginTop: 20 },
});Docs entries used in this lesson
Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. Which function opens the photo gallery?
2. Which option allows selecting multiple photos?
Hands-on tasks in the game
- Click in order
Click the image picker configuration elements that allow picking only images:
- Code editor
Complete the code with Alert and ImagePicker.