Skip to main content
Glama
image-picker.md10.7 kB
--- title: Use an image picker description: In this tutorial, learn how to use Expo Image Picker. hasVideoLink: true --- React Native provides built-in components as standard building blocks, such as ``, `<Text>`, and `<Pressable>`. We are building a feature to select an image from the device's media gallery. This isn't possible with the core components and we'll need a library to add this feature in our app. We'll use [`expo-image-picker`](/versions/latest/sdk/imagepicker), a library from Expo SDK. > `expo-image-picker` provides access to the system's UI to select images and videos from the phone's library. --- <Step label="1"> ## Install expo-image-picker To install the library, run the following command: > **info** **Tip:** Any time we install a new library in our project, stop the development server by pressing <kbd>Ctrl</kbd> + <kbd>c</kbd> in the terminal and then run the installation command. After the installation completes, we can start the development server again by running `npx expo start` from the same terminal window. </Step> <Step label="2"> ## Pick an image from the device's media library `expo-image-picker` provides `launchImageLibraryAsync()` method to display the system UI by choosing an image or a video from the device's media library. We'll use the primary themed button created in the previous chapter to select an image from the device's media library and create a function to launch the device's image library to implement this functionality. In **app/(tabs)/index.tsx**, import `expo-image-picker` library and create a `pickImageAsync()` function inside the `Index` component: {/* prettier-ignore */} ```tsx app/(tabs)/index.tsx|collapseHeight=440 // ...rest of the import statements remain unchanged /* @tutinfo Import <CODE>ImagePicker</CODE>. */ import * as ImagePicker from 'expo-image-picker';/* @end */ /* @tutinfo Pass image picker options to <CODE>launchImageLibraryAsync()</CODE> */ const pickImageAsync = async () => { let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['images'], allowsEditing: true, quality: 1, }); if (!result.canceled) { /* @tutinfo If the image is picked, print its information in terminal window. */ console.log(result); /* @end */ } else { /* @tutinfo If the user does not pick an image, show an alert. */ alert('You did not select any image.'); /* @end */ } }; /* @end */ // ...rest of the code remains same } ``` Let's learn what the above code does: - The `launchImageLibraryAsync()` receives an object to specify different options. This object is the [`ImagePickerOptions`](/versions/latest/sdk/imagepicker/#imagepickeroptions) object, which we are passing when invoking the method. - When `allowsEditing` is set to `true`, the user can crop the image during the selection process on Android and iOS. </Step> <Step label="3"> ## Update the button component On pressing the primary button, we'll call the `pickImageAsync()` function on the `Button` component. Update the `onPress` prop of the `Button` component in **components/Button.tsx**: {/* prettier-ignore */} ```tsx components/Button.tsx type Props = { label: string; theme?: 'primary'; /* @tutinfo Define the type for <CODE>onPress</CODE> prop. */ onPress?: () => void; /* @end */ }; if (theme === 'primary') { return ( <View style={[ styles.buttonContainer, { borderWidth: 4, borderColor: '#ffd33d', borderRadius: 18 }, ]}> <Pressable style={[styles.button, { backgroundColor: '#fff' }]} onPress={/* @tutinfo */onPress/* @end */}> <Text style={[styles.buttonLabel, { color: '#25292e' }]}>{label}</Text> </Pressable> ); } return ( <Pressable style={styles.button} onPress={() => alert('You pressed a button.')}> <Text style={styles.buttonLabel}>{label}</Text> </Pressable> ); } const styles = StyleSheet.create({ buttonContainer: { width: 320, height: 68, marginHorizontal: 20, alignItems: 'center', justifyContent: 'center', padding: 3, }, button: { borderRadius: 10, width: '100%', height: '100%', alignItems: 'center', justifyContent: 'center', flexDirection: 'row', }, buttonIcon: { paddingRight: 8, }, buttonLabel: { color: '#fff', fontSize: 16, }, }); ``` In **app/(tabs)/index.tsx**, add the `pickImageAsync()` function to the `onPress` prop on the first `<Button>`. {/* prettier-ignore */} ```tsx app/(tabs)/index.tsx const PlaceholderImage = require('@/assets/images/background-image.png'); const pickImageAsync = async () => { let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['images'], allowsEditing: true, quality: 1, }); if (!result.canceled) { console.log(result); } else { alert('You did not select any image.'); } }; return ( <View style={styles.imageContainer}> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#25292e', alignItems: 'center', }, imageContainer: { flex: 1, }, footerContainer: { flex: 1 / 3, alignItems: 'center', }, }); ``` The `pickImageAsync()` function invokes `ImagePicker.launchImageLibraryAsync()` and then handles the result. The `launchImageLibraryAsync()` method returns an object containing information about the selected image. Here is an example of the `result` object and the properties it contains: <Tab label="Android"> ```json collapseHeight=280 { "assets": [ { "assetId": null, "base64": null, "duration": null, "exif": null, "fileName": "ea574eaa-f332-44a7-85b7-99704c22b402.jpeg", "fileSize": 4513577, "height": 4570, "mimeType": "image/jpeg", "rotation": null, "type": "image", "uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252FStickerSmash-13f21121-fc9d-4ec6-bf89-bf7d6165eb69/ImagePicker/ea574eaa-f332-44a7-85b7-99704c22b402.jpeg", "width": 2854 } ], "canceled": false } ``` </Tab> <Tab label="iOS"> ```json collapseHeight=280 { "assets": [ { "assetId": "99D53A1F-FEEF-40E1-8BB3-7DD55A43C8B7/L0/001", "base64": null, "duration": null, "exif": null, "fileName": "IMG_0004.JPG", "fileSize": 2548364, "height": 1669, "mimeType": "image/jpeg", "type": "image", "uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252FStickerSmash-13f21121-fc9d-4ec6-bf89-bf7d6165eb69/ImagePicker/ea574eaa-f332-44a7-85b7-99704c22b402.jpeg", "width": 1668 } ], "canceled": false } ``` </Tab> <Tab label="web"> ```json { "assets": [ { "fileName": "some-image.png", "height": 720, "mimeType": "image/png", "uri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABQAA" } ], "canceled": false } ``` </Tab> </Step> ## Use the selected image The `result` object provides the `assets` array, which contains the `uri` of the selected image. Let's take this value from the image picker and use it to show the selected image in the app. Modify the **app/(tabs)/index.tsx** file: 1. Declare a state variable called `selectedImage` using the [`useState`](https://react.dev/learn/state-a-components-memory#adding-a-state-variable) hook from React. We'll use this state variable to hold the URI of the selected image. 2. Update the `pickImageAsync()` function to save the image URI in the `selectedImage` state variable. 3. Pass the `selectedImage` as a prop to the `ImageViewer` component. {/* prettier-ignore */} ```tsx app/(tabs)/index.tsx /* @tutinfo Import <CODE>useState</CODE> hook from <CODE>react<CODE>.*/ /* @end */ const PlaceholderImage = require('@/assets/images/background-image.png'); /* @tutinfo Create a state variable that will hold the value of selected image. */ const [selectedImage, setSelectedImage] = useState<string | undefined>(undefined); /* @end */ const pickImageAsync = async () => { let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['images'], allowsEditing: true, quality: 1, }); if (!result.canceled) { /* @tutinfo Pick the first uri from the <CODE>assets</CODE> array. Also, there is only one image selected at a time so you don't have to change this. */ setSelectedImage(result.assets[0].uri); /* @end */ } else { alert('You did not select any image.'); } }; return ( <View style={styles.container}> <View style={styles.imageContainer}> /* @tutinfo Pass the selected image URI to the <CODE>ImageViewer</CODE> component. */ /* @end */ </View> <View style={styles.footerContainer}> </View> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#25292e', alignItems: 'center', }, imageContainer: { flex: 1, }, footerContainer: { flex: 1 / 3, alignItems: 'center', }, }); ``` Pass the `selectedImage` prop to the `ImageViewer` component to display the selected image instead of a placeholder image. 1. Modify the **components/ImageViewer.tsx** file to accept the `selectedImage` prop. 2. The source of the image is getting long, so let's also move it to a separate variable called `imageSource`. 3. Pass `imageSource` as the value of the `source` prop on the `Image` component. {/* prettier-ignore */} ```tsx components/ImageViewer.tsx type Props = { imgSource: ImageSourcePropType; /* @tutinfo */ selectedImage?: string; /* @end */ }; /* @tutinfo If the selected image is not null, show the image from the device, otherwise, show the placeholder image. */ const imageSource = selectedImage ? { uri: selectedImage } : imgSource; /* @end */ /* @tutinfo <CODE>imgSource</CODE> replaced by <CODE>imageSource</CODE>. */ return ; /* @end */ } const styles = StyleSheet.create({ image: { width: 320, height: 440, borderRadius: 18, }, }); ``` In the above snippet, the Image component uses a conditional operator to load the image's source. The picked image is a [`uri` string](https://reactnative.dev/docs/images#network-images), not a local asset like the placeholder image. Let's take a look at our app now: > The images used for the example app in this tutorial were picked from [Unsplash](https://unsplash.com). ## Summary

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jaksm/expo-docs-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server