Access Camera Roll With React Native
I started learning React Native 2 months ago and I found out that most of the issues I encountered while trying to implement features such as taking a picture, accessing photos on a phone, chats, authentication were a bit difficult to achieve because the React Native documentation sometimes didn't do justice in explaining these concepts. I had to resort to using libraries to quickly achieve what I set out to achieve.
I've decided to document most of the features I've implemented using the React Native APIs. Here is a simple tutorial using the cameral roll API to access photos in your device. You should check out the React Native documentation.
Setting up React Native
If you haven't built any React Native application, this is a really simple tutorial to get started with. Since I'll be building for the IOS platform, the set up will gear towards that platform.Go to the React Native Site and follow the steps on Building projects with native code.
You can also use the create-react-native-app to have a quick setup.
By now, you should have your app up and running on either the emulator or iPhone device. Here is my folder structure.
In my project folder, I created a component folder that has 3 components namely:
- CameraScreen.js - add photo button and access to camera roll occurs here.
- ViewPhotos.js - displays photos from your iPhone.
- SelectedPhoto.js - shows the selected photo.
Yes I know, my naming is 😀. But you get the whole idea. I removed almost all the boilerplate code in my index.ios.js, you should have something like this:
index.ios.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
import CameraScreen from './component/CameraScreen';
export default class cameraRollExample extends Component {
render() {
return (
<CameraScreen/>
);
}
}
AppRegistry.registerComponent('cameraRollExample', () => cameraRollExample);
In my CameraScreen.js, I've made a simple UI that has the add photo button, and I've also imported the CameraRoll module from React Native.
CameraScreen.js
import React, { Component } from 'react';
import {
CameraRoll,
Image,
StyleSheet,
TouchableHighlight,
View,
} from 'react-native';
class CameraScreen extends Component {
render() {
return (
<View style={styles.container}>
<TouchableHighlight>
<Image
source={require('../assets/addPhoto.png')} />
</TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
});
export default CameraScreen;
You should have this:
In order to access the photos, you need a click event. Add the onPress prop to your button and call the method getPhotosFromGallery() on it.
//...
render() {
return (
<View style={styles.container}>
<TouchableHighlight
onPress={() => this.getPhotosFromGallery()}>
<Image
source={require('../assets/addPhoto.png')} />
</TouchableHighlight>
</View>
);
}
getPhotosFromGallery()
//...
getPhotosFromGallery() {
CameraRoll.getPhotos({ first: 1000000 })
.then(res => {
console.log(res, "images data")
})
}
//...
The object inside getPhotos({ first: 1000000})
is used to specify the number of images you want to get from the gallery. When you run the app, you will get this error:
This error occurs because you haven't added or linked the camera roll library to your Build Phases in Xcode. This is known as manual linking. To do this,
- go to your project folder
- open the IOS folder
- go to the file that has
.xcodeproj
as the extension, in my case it'scameraRollExample.xcodeproj
- open this file in your Xcode.
Once it's opened, you should have this.
Next, you need to drag the RCTCameraRoll.xcodeproj
in your project folder to Xcode. Here is a simple diagram on where to find this file.
Drag the RCTCameraRoll.xcodeproj file to the libraries file in Xcode and then click on Build Phases on the top right-hand corner in Xcode. Click the drop down of Link Binary With Libraries, then the + sign to add the libRCTCameraRoll.a
.
Run the build and restart your emulator or device. You should see the image object in you log.
In order to see the images, you need the uri
in the image object. Here is an updated version of the CameraRoll.js.
CameraRoll.js
//...
import ViewPhotos from './ViewPhotos';
class CameraScreen extends Component {
state = {
showPhotoGallery: false,
photoArray: []
}
getPhotosFromGallery() {
CameraRoll.getPhotos({ first: 1000000 })
.then(res => {
let photoArray = res.edges;
this.setState({ showPhotoGallery: true, photoArray: photoArray })
})
}
render() {
if (this.state.showPhotoGallery) {
return (
<ViewPhotos
photoArray={this.state.photoArray} />
)
}
return (
<View style={styles.container}>
<TouchableHighlight
onPress={() => this.getPhotosFromGallery()}>
<Image
source={require('../assets/addPhoto.png')} />
</TouchableHighlight>
</View>
);
}
}
//...
I imported the ViewPhotos.js, in the code snippets above. This is to display the images in a list view.
ViewPhotos.js
import React, { Component } from 'react';
import {
Image,
View,
ListView,
StyleSheet,
Text,
TouchableHighlight
} from 'react-native';
import SelectedPhoto from './SelectedPhoto';
class ViewPhotos extends Component {
state = {
ds: new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
}),
showSelectedPhoto: false,
uri: ''
}
renderRow(rowData) {
const { uri } = rowData.node.image;
return (
<TouchableHighlight
onPress={() => this.setState({ showSelectedPhoto: true, uri: uri })}>
<Image
source={{ uri: rowData.node.image.uri }}
style={styles.image} />
</TouchableHighlight>
)
}
render() {
const { showSelectedPhoto, uri } = this.state;
if (showSelectedPhoto) {
return (
<SelectedPhoto
uri={uri} />
)
}
return (
<View style={{ flex: 1 }}>
<View style={{ alignItems: 'center', marginTop: 15 }}>
<Text style={{ fontSize: 20, fontWeight: '600' }}>Pick A Photo </Text>
</View>
<ListView
contentContainerStyle={styles.list}
dataSource={this.state.ds.cloneWithRows(this.props.photoArray)}
renderRow={(rowData) => this.renderRow(rowData)}
enableEmptySections={true} />
</View>
);
}
}
const styles = StyleSheet.create({
list: {
flexDirection: 'row',
flexWrap: 'wrap'
},
image: {
width: 110,
height: 120,
marginLeft: 10,
marginTop: 10,
borderRadius: 5,
borderWidth: 1,
borderColor: '#979797'
}
})
export default ViewPhotos;
Here is the screen:
When you click or select a photo from the list, you will see the selected photo in the SelectedPhoto.js component.
SelectedPhoto.js
import React from 'react';
import {
Image,
View,
StyleSheet,
Text,
TouchableHighlight
} from 'react-native';
const SelectedPhoto = (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 SelectedPhoto;
Conclusion
I've run the app on iPhone 6s and iPhone 6s plus. I would love to see builds from other versions and get your feedback and experience. Here is the github repo with the complete app. Gracias 😇
Thanks for reading and feel free to like and share.
Thanks for this tutorial article. Simple and to the point. Easy to understand the use of CameraRoll Component from react native package. The use of Camera Roll with other Ui layout screens is exemplary. Hence, this is a great article to learn about React Native Camera Roll.
Nice Tutorial, can you share tutorial on how to create video gallery with react native
How can I render library image by 40 and then 40 using flatlist. I have tried the flatlist but the images get flickered and in some cases, all the images are not displayed in the screen. If I give a high values does it make any issues. (i.e) for an user they have 1500 images in thier gallery. But they have more than 1000 images. In this case the above not works and need to add any other methods here. Can you explain it. I have added renderPhotos method to render 40 by 40. But it not works well. Gets flickering in the screen