19
When learning React Native, we find that majority of issues are encountered while trying to implement features such as taking a picture, accessing photos from the mobile device, chats, authentication, etc. These issues are a bit hard to resolve as the React Native documentation does not explain these concepts very well. Thus, we have to use libraries to achieve any of the above functionalities.
In this guide, we will highlight the features implemented using React Native APIs. This guide will help you implement the camera roll API for accessing pictures on a device. Feel free to also check out the official React Native documentation.
For someone just starting to build React Native apps, this should be a fairly simple guide to get started with. We'll be building our app for IOS, so the setup is according to that platform. We can go to the React Native site and follow the steps to build projects with native code.
Also for a quick setup, we can use the create-react-native-app.
By now, the app should be up and running on either the emulator or iPhone device. Below is how the folder structure should look. We have a component folder with three components as below:
CamScreen.js - The add picture button and accessing the camera roll take place here.
ViewPictures.js - Displays pictures from your iPhone.
SelectedPicture.js - Displays the selected picture.
We have the boilerplate code in our index.ios.js. It should look something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
import React, { Component } from 'react'; import { AppRegistry, StyleSheet, Text, View } from 'react-native'; import CamScreen from './component/CamScreen'; export default class camRollExample extends Component { render() { return ( <CamScreen/> ); } } AppRegistry.registerComponent('camRollExample', () => camRollExample);
In CamScreen.js, we have a simple interface where we have the add picture button, and we also import the CameraRoll module from React Native.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
import React, { Component } from 'react'; import { CameraRoll, Image, StyleSheet, TouchableHighlight, View, } from 'react-native'; class CamScreen extends Component { render() { return ( <View style={styles.container}> <TouchableHighlight> <Image source={require('../assets/addPicture.png')} /> </TouchableHighlight> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center' } }); export default CamScreen;
For accessing photos, we need a click event. Let's add the onPress
prop to the button and a handler method called getPicturesFromGallery()
.
1 2 3 4 5 6 7 8 9 10 11 12
//... render() { return ( <View style={styles.container}> <TouchableHighlight onPress={() => this.getPicturesFromGallery()}> <Image source={require('../assets/addPicture.png')} /> </TouchableHighlight> </View> ); }
1 2 3 4 5 6 7 8
//... getPicturesFromGallery() { CameraRoll.getPhotos({ first: 5000 }) .then(res => { console.log(res, "images data") }) } //...
The object inside the getPhotos({ first: 5000 })
is used to specify the number of images that we want to get from the gallery. When we run the app, we'll encounter an error:
"Cannot read property 'getPhotos' of undefined"
The above error happens because the camera roll library has not been added or linked to our build phases in Xcode. To fix the error, we'll:
Go to our project directory
Open IOS directory
Navigate to the file that has .xcodeproj as the extension. In our case, it should be camRollExample.xcodeproj
Open this file in Xcode.
Next, we should drag RCTCamRoll.xcodeproj in our project directory to Xcode.
Let's drag the RCTCamRoll.xcodeproj file to libraries file in Xcode. We can then click on Build Phases located in the top right-hand corner in Xcode. Let's click the dropdown next to Link Binary With Libraries, then the + sign to add libRCTCamRoll.a.
We can then run the build and restart our emulator or device. The image object should be visible in our log. To check the images, we need to have the uri in the image object. Here is an updated version of CameraRoll.js.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
//... import ViewPictures from './ViewPictures'; class CamScreen extends Component { state = { showPhotoGallery: false, pictureArray: [] } getPicturesFromGallery() { CameraRoll.getPhotos({ first: 5000}) .then(res => { let pictureArray = res.edges; this.setState({ showPhotoGallery: true, pictureArray: pictureArray }) }) } render() { if (this.state.showPhotoGallery) { return ( <ViewPictures pictureArray={this.state.pictureArray} /> ) } return ( <View style={styles.container}> <TouchableHighlight onPress={() => this.getPicturesFromGallery()}> <Image source={require('../assets/addPicture.png')} /> </TouchableHighlight> </View> ); } } //...
In the above code snippets, we just imported ViewPictures.js. This is for displaying the images inside of a list view.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
import React, { Component } from 'react'; import { Image, View, ListView, StyleSheet, Text, TouchableHighlight } from 'react-native'; import SelectedPicture from './SelectedPicture'; class ViewPictures extends Component { state = { ds: new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 }), showSelectedPicture: false, uri: '' } renderRow(rowData) { const { uri } = rowData.node.image; return ( <TouchableHighlight onPress={() => this.setState({ showSelectedPicture: true, uri: uri })}> <Image source={{ uri: rowData.node.image.uri }} style={styles.image} /> </TouchableHighlight> ) } render() { const { showSelectedPicture, uri } = this.state; if (showSelectedPicture) { return ( <SelectedPicture uri={uri} /> ) } return ( <View style={{ flex: 1 }}> <View style={{ alignItems: 'center', marginTop: 15 }}> <Text style={{ fontSize: 30, fontWeight: '700' }}>Pick A Picture !</Text> </View> <ListView contentContainerStyle={styles.list} dataSource={this.state.ds.cloneWithRows(this.props.pictureArray)} renderRow={(rowData) => this.renderRow(rowData)} enableEmptySections={true} /> </View> ); } } const styles = StyleSheet.create({ list: { flexDirection: 'row', flexWrap: 'wrap' }, image: { width: 120, height: 130, marginLeft: 15, marginTop: 15, borderRadius: 6, borderWidth: 2, borderColor: '#efefef' } }) export default ViewPictures;
When we click or select a picture from the list, the selected picture will get displayed in the SelectedPicture.js component.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
import React from 'react'; import { Image, View, StyleSheet, Text, TouchableHighlight } from 'react-native'; const SelectedPicture = (props) => { const { uri } = props; return ( <View style={styles.container}> <Image source={{uri: uri}} style={styles.image}/> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center' }, image: { height: 300, width: 200 } }); export default SelectedPicture;
Having run the app on both iPhone 6s and iPhone 6s plus, we can extend the test to other devices and verify how it performs on other platforms.
19