DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • How to Build Scalable Mobile Apps With React Native: A Step-by-Step Guide
  • Cross-Platform Mobile Application Development: Evaluating Flutter, React Native, HTML5, Xamarin, and Other Frameworks
  • Common Problems in Redux With React Native
  • How To Integrate the Stripe Payment Gateway Into a React Native Application

Trending

  • Testing SingleStore's MCP Server
  • Simplify Authorization in Ruby on Rails With the Power of Pundit Gem
  • Scalability 101: How to Build, Measure, and Improve It
  • Comparing SaaS vs. PaaS for Kafka and Flink Data Streaming
  1. DZone
  2. Coding
  3. JavaScript
  4. How to Use a Camera in React Native

How to Use a Camera in React Native

By 
krissanawatt kaewsanmunag user avatar
krissanawatt kaewsanmunag
·
Jun. 16, 20 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
9.7K Views

Join the DZone community and get the full member experience.

Join For Free

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
x
 
1
$yarn add expo-camera expo-av


or

Shell
xxxxxxxxxx
1
 
1
$npm install expo-camera expo-av


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.

React Native React (JavaScript library) mobile app

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

Opinions expressed by DZone contributors are their own.

Related

  • How to Build Scalable Mobile Apps With React Native: A Step-by-Step Guide
  • Cross-Platform Mobile Application Development: Evaluating Flutter, React Native, HTML5, Xamarin, and Other Frameworks
  • Common Problems in Redux With React Native
  • How To Integrate the Stripe Payment Gateway Into a React Native Application

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!