{{announcement.body}}
{{announcement.title}}

How to Use a Camera in React Native

DZone 's Guide to

How to Use a Camera in React Native

In this article, we will describe the basic implementation of Capturing Photos and Videos in React Native.

· Web Dev Zone ·
Free Resource

Capturing Memories! Camera in our smartphones allows us to quickly capture amazing moments in our lives. Moments which we most likely can never return to, but we can safely capture them up in the form of photos and videos. we are therefore left with a desire to share this amazing moment with our loved ones through our favorite mobile apps.

Building your next mobile app, you might want to add the capability to capture photos and videos. You also might not be exactly sure how to implement this. Well, look no further as we have recently implemented this feature in our social apps. You might want to check out how we have seamlessly implemented the camera feature with React Native.

I will describe here, the basic implementation of Capturing Photos and Videos in React Native.

Required Packages

For this project, we will be using:

  • expo-camera. This package is required for capturing photos and videos.
  • expo-av. Here, we will import video from this module to play our recorded video.

Now you can go ahead and install both packages.

Shell


or

Shell


Implementing the Camera Feature

Adding the camera component to a view in your project is quite straight forward.

JavaScript
 




x
233


1
import React, { useState, useRef, useEffect } from "react";
2
import {
3
  StyleSheet,
4
  Dimensions,
5
  View,
6
  Text,
7
  TouchableOpacity,
8
  SafeAreaView,
9
} from "react-native";
10
import { Camera } from "expo-camera";
11
import { Video } from "expo-av";
12
 
          
13
const WINDOW_HEIGHT = Dimensions.get("window").height;
14
 
          
15
const closeButtonSize = Math.floor(WINDOW_HEIGHT * 0.032);
16
const captureSize = Math.floor(WINDOW_HEIGHT * 0.09);
17
 
          
18
export default function App() {
19
  const [hasPermission, setHasPermission] = useState(null);
20
  const [cameraType, setCameraType] = useState(Camera.Constants.Type.back);
21
  const [isPreview, setIsPreview] = useState(false);
22
  const [isCameraReady, setIsCameraReady] = useState(false);
23
  const [isVideoRecording, setIsVideoRecording] = useState(false);
24
  const [videoSource, setVideoSource] = useState(null);
25
  const cameraRef = useRef();
26
 
          
27
  useEffect(() => {
28
    (async () => {
29
      const { status } = await Camera.requestPermissionsAsync();
30
      setHasPermission(status === "granted");
31
    })();
32
  }, []);
33
 
          
34
  const onCameraReady = () => {
35
    setIsCameraReady(true);
36
  };
37
 
          
38
  const takePicture = async () => {
39
    if (cameraRef.current) {
40
      const options = { quality: 0.5, base64: true, skipProcessing: true };
41
      const data = await cameraRef.current.takePictureAsync(options);
42
      const source = data.uri;
43
      if (source) {
44
        await cameraRef.current.pausePreview();
45
        setIsPreview(true);
46
        console.log("picture source", source);
47
      }
48
    }
49
  };
50
 
          
51
  const recordVideo = async () => {
52
    if (cameraRef.current) {
53
      try {
54
        const videoRecordPromise = cameraRef.current.recordAsync();
55
 
          
56
        if (videoRecordPromise) {
57
          setIsVideoRecording(true);
58
          const data = await videoRecordPromise;
59
          const source = data.uri;
60
          if (source) {
61
            setIsPreview(true);
62
            console.log("video source", source);
63
            setVideoSource(source);
64
          }
65
        }
66
      } catch (error) {
67
        console.warn(error);
68
      }
69
    }
70
  };
71
 
          
72
  const stopVideoRecording = () => {
73
    if (cameraRef.current) {
74
      setIsPreview(false);
75
      setIsVideoRecording(false);
76
      cameraRef.current.stopRecording();
77
    }
78
  };
79
 
          
80
  const switchCamera = () => {
81
    if (isPreview) {
82
      return;
83
    }
84
    setCameraType((prevCameraType) =>
85
      prevCameraType === Camera.Constants.Type.back
86
        ? Camera.Constants.Type.front
87
        : Camera.Constants.Type.back
88
    );
89
  };
90
 
          
91
  const cancelPreview = async () => {
92
    await cameraRef.current.resumePreview();
93
    setIsPreview(false);
94
    setVideoSource(null);
95
  };
96
 
          
97
  const renderCancelPreviewButton = () => (
98
    <TouchableOpacity onPress={cancelPreview} style={styles.closeButton}>
99
      <View style={[styles.closeCross, { transform: [{ rotate: "45deg" }] }]} />
100
      <View
101
        style={[styles.closeCross, { transform: [{ rotate: "-45deg" }] }]}
102
      />
103
    </TouchableOpacity>
104
  );
105
 
          
106
  const renderVideoPlayer = () => (
107
    <Video
108
      source={{ uri: videoSource }}
109
      shouldPlay={true}
110
      style={styles.media}
111
    />
112
  );
113
 
          
114
  const renderVideoRecordIndicator = () => (
115
    <View style={styles.recordIndicatorContainer}>
116
      <View style={styles.recordDot} />
117
      <Text style={styles.recordTitle}>{"Recording..."}</Text>
118
    </View>
119
  );
120
 
          
121
  const renderCaptureControl = () => (
122
    <View style={styles.control}>
123
      <TouchableOpacity disabled={!isCameraReady} onPress={switchCamera}>
124
        <Text style={styles.text}>{"Flip"}</Text>
125
      </TouchableOpacity>
126
      <TouchableOpacity
127
        activeOpacity={0.7}
128
        disabled={!isCameraReady}
129
        onLongPress={recordVideo}
130
        onPressOut={stopVideoRecording}
131
        onPress={takePicture}
132
        style={styles.capture}
133
      />
134
    </View>
135
  );
136
 
          
137
  if (hasPermission === null) {
138
    return <View />;
139
  }
140
 
          
141
  if (hasPermission === false) {
142
    return <Text style={styles.text}>No access to camera</Text>;
143
  }
144
 
          
145
  return (
146
    <SafeAreaView style={styles.container}>
147
      <Camera
148
        ref={cameraRef}
149
        style={styles.container}
150
        type={cameraType}
151
        flashMode={Camera.Constants.FlashMode.on}
152
        onCameraReady={onCameraReady}
153
        onMountError={(error) => {
154
          console.log("cammera error", error);
155
        }}
156
      />
157
      <View style={styles.container}>
158
        {isVideoRecording && renderVideoRecordIndicator()}
159
        {videoSource && renderVideoPlayer()}
160
        {isPreview && renderCancelPreviewButton()}
161
        {!videoSource && !isPreview && renderCaptureControl()}
162
      </View>
163
    </SafeAreaView>
164
  );
165
}
166
 
          
167
const styles = StyleSheet.create({
168
  container: {
169
    ...StyleSheet.absoluteFillObject,
170
  },
171
  closeButton: {
172
    position: "absolute",
173
    top: 35,
174
    left: 15,
175
    height: closeButtonSize,
176
    width: closeButtonSize,
177
    borderRadius: Math.floor(closeButtonSize / 2),
178
    justifyContent: "center",
179
    alignItems: "center",
180
    backgroundColor: "#c4c5c4",
181
    opacity: 0.7,
182
    zIndex: 2,
183
  },
184
  media: {
185
    ...StyleSheet.absoluteFillObject,
186
  },
187
  closeCross: {
188
    width: "68%",
189
    height: 1,
190
    backgroundColor: "black",
191
  },
192
  control: {
193
    position: "absolute",
194
    flexDirection: "row",
195
    bottom: 38,
196
    width: "100%",
197
    alignItems: "center",
198
    justifyContent: "center",
199
  },
200
  capture: {
201
    backgroundColor: "#f5f6f5",
202
    borderRadius: 5,
203
    height: captureSize,
204
    width: captureSize,
205
    borderRadius: Math.floor(captureSize / 2),
206
    marginHorizontal: 31,
207
  },
208
  recordIndicatorContainer: {
209
    flexDirection: "row",
210
    position: "absolute",
211
    top: 25,
212
    alignSelf: "center",
213
    justifyContent: "center",
214
    alignItems: "center",
215
    backgroundColor: "transparent",
216
    opacity: 0.7,
217
  },
218
  recordTitle: {
219
    fontSize: 14,
220
    color: "#ffffff",
221
    textAlign: "center",
222
  },
223
  recordDot: {
224
    borderRadius: 3,
225
    height: 6,
226
    width: 6,
227
    backgroundColor: "#ff0000",
228
    marginHorizontal: 5,
229
  },
230
  text: {
231
    color: "#fff",
232
  },
233
});



After adding this code, we should have our camera display ready. Make sure you run it on an actual device.

Program running on app

The implementation here is very simple and the logic has been broken down into the core methods below:

Before we analyze the core methods that make up the logic of our camera project, we should take note of where we have displayed the “Camera” component instance (<Camera… />).

Here we passed the already defined cameraRef to the ref prop of our Camera component.

Doing this, we now have access to beautiful methods like takePictureAsync(), recordAysnc()… on the cameraRef we had previously passed to the ref prop. This method will be key in helping us achieve the desired goal like taking a picture, recording a video and more.

  • onCameraReady(). This callback method is implemented with the purpose of deciding when the camera is ready to capture photos or videos. You should note that it is important we check if this method was called before capturing pictures in any form.
  • takePicture(). With the help of “takePictureAsync()” called on the ref of the Camera component instance (cameraRef.current.takePictureAsync), we are able to successfully capture a picture with this method.
  • recordVideo(). This method act similarly to the takePicture() method. Triggered by onLongPress callback of our capture component, we capture moments in form of videos with the help of the recordAsync method called also on the ref of the Camera component instance  (cameraRef.current.recordAsync()).
  • stopVideoRecording(). This method is triggered by the user to stop the recording of a video.
  • switchCamera(). This method switch between the front and back camera of ur device.
  • cancelPreview(). This method cancels any form of photo or video preview is it a photo or video.

All the render methods such as renderCancelPreviewButton(), renderVideoPlayer()… simply renders a component for display on ur mobile screen.

Summary

Before we render any Component for display, we request necessary permissions with “requestPermissionsAsync” called on the instance of the Camera component (Camera.requestPermissionsAsync()). This method is called in the useEffect method. Our useEffect method is triggered only when the component is initially mounted.

We have implemented a simple condition rendering with our components for display. Here, only when we are previewing, we render a cancel button to cancel the preview of a photo or video after it has been captured. We render an indicator when we are recording. A video player after a video has been recorded and we have a video source.

We render a capture button only when we do not have a video source and we are not previewing.

User clicks on the capture button to record.

User can also press and hold on the capture button to record a video. Press out to stop recording and preview the recorded video.

Press the flip text to switch camera.

Conclusion

A picture is worth a thousand words and having the capability to capture photos and videos in your app is an essential feature. Photos and videos are believed to be the new keyboard, conveying more messages that can not be captured by words.

Remember to check out any of our demo apps to see how we have gone beyond the basic implementation of this feature.

Topics:
mobile development, react, react native

Published at DZone with permission of krissanawatt kaewsanmunag . See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}