Cómo crear una aplicación de cámara con Expo y React Native

Si no está familiarizado con expo, es un cliente que lo ayuda a crear aplicaciones React Native con menos complejidad de construcción. También lo ayuda a lidiar con el estrés de instalar y configurar su entorno para ejecutar React Native.

En este tutorial, crearemos una aplicación de cámara simple en la que el usuario puede tomar fotografías, ver vistas previas de sus fotografías, usar el modo flash y cambiar entre la cámara frontal y la trasera.

Prerrequisitos

Expo no requiere mucho para comenzar a construir su primera aplicación React Native. Puede obtener más información sobre la instalación de expo y expo-cli aquí en los documentos.

Nota: en este tutorial, usaré macOS e iOS. También puede usar Android, no hay mucha diferencia al usar expo en este momento.

Puede instalar expo y expo-cli globalmente ejecutando el siguiente comando:

npm install --global expo-cli

Expo requiere Nodejs para ejecutarse. Puede ejecutar la última versión en el sitio web oficial aquí.

Empezando

Una vez que haya instalado Expo y Nodejs, puede comenzar a iniciar un nuevo proyecto de Expo con el siguiente comando:

expo init expo-camera-app

Cómo instalar los paquetes y ejecutar la aplicación

Expo nos proporciona una aplicación cliente donde podemos ejecutar y ver la vista previa de la aplicación que estamos creando. Está disponible tanto en App Store como en Google Play para descargar.

Esta es la interfaz de la aplicación.

Cómo iniciar un proyecto de expo

Vaya al directorio de la aplicación y ejecute la aplicación.

cd expo-camera-app 

Se le harán algunas preguntas para seleccionar la plantilla predeterminada para la aplicación. En este tutorial, simplemente seleccionamos una opción en blanco (TypeScript), pero nuevamente, usted es libre de elegir lo que sea adecuado para usted.

Ejecutar la aplicación

Después de iniciar el proyecto, podemos ejecutar la aplicación con expo run

Esto abrirá una ventana en su navegador donde podrá ver los registros. También generará un código QR que puede escanear para ejecutar la aplicación en su dispositivo.

Lo bueno de expo es que no es necesario instalar y configurar los simuladores para ejecutar la aplicación. Todavía le da la opción de ejecutar expo en el simulador, pero debe instalar y configurar el simulador usted mismo.

Volver a nuestra aplicación. Suponiendo que haya ejecutado correctamente la aplicación en el dispositivo, esta será la pantalla predeterminada:

Abra el directorio de la aplicación en su editor de código favorito. Estoy usando VS Code.

El App.tsxse verá así:

import {StatusBar} from 'expo-status-bar' import React from 'react' import {StyleSheet, Text, View} from 'react-native' export default function App() { return (  Open up App.tsx to start working on your app!   ) } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center' } }) 

Cómo crear la interfaz de usuario

Después de tener el proyecto en ejecución, ahora es el momento de comenzar a crear una interfaz de usuario.

Instalar expo-camera

El siguiente paso es instalar expo-camera, así:

expo install expo-camera

Crearemos una interfaz de usuario simple que permitirá al usuario iniciar el proceso de uso de la cámara.

import {StatusBar} from 'expo-status-bar' import React from 'react' import {StyleSheet, Text, View, TouchableOpacity} from 'react-native' export default function App() { return (     Take picture      ) } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center' } }) 

Es una interfaz de usuario simple: importamos TouchableOpacitypara el botón y hacemos un estilo simple. Si se pregunta cómo funciona el estilo en React Native, puede consultar mis dos artículos aquí:

  • Estilo en React Native
  • Desmitificando Flexbox en React Native

Ahora tenemos que usar un useStategancho para administrar el estado y mostrar la vista de la cámara cuando el usuario presiona el botón para tomar una foto .

   Take picture  
 const [startCamera,setStartCamera] = React.useState(false) const __startCamera = ()=>{ }

Hay dos cosas importantes que tenemos que hacer cuando el usuario presiona el botón:

  • Pide permiso para acceder a la cámara. En el desarrollo móvil, el acceso a muchas API nativas y funciones móviles a menudo está restringido por los permisos del usuario y la privacidad. Es algo a lo que tienes que acostumbrarte al desarrollar aplicaciones móviles.
  • Change the state and present the camera.

Let's import the camera module from expo-camera with this command:

import {Camera} from 'expo-camera'

And add the camera view, like this:

  { camera = r }} >

We can use ref to access the camera's methods:

let camera: Camera

When the take picture button is pressed the __startCamera function will be called:

 const __startCamera = async () => { const {status} = await Camera.requestPermissionsAsync() if(status === 'granted'){ // do something }else{ Alert.alert("Access denied") }

The function will ask for permission first. If the user grant access to the camera, we can proceed and open the camera. If not, we show a simple alert.

Add the camera component

Let's display the camera when the user grants access to the device's camera.

 const __startCamera = async () => { const {status} = await Camera.requestPermissionsAsync() if (status === 'granted') { // start the camera setStartCamera(true) } else { Alert.alert('Access denied') } }

We have to make some changes to the UI and add a conditional rendering. We display the camera only when the user requests it, otherwise we display the default screen.

 {startCamera ? (  { camera = r }} > ) : (    Take picture    )}

Cool, now we need to add a button so we can take the actual picture.

Add the capture button

This is a simple View inside the camera view that has an absolute position. So we make sure that it is always on the top of the camera.

How to take a picture

The app should take a picture when capture button is pressed. That function will look like the below:

 const __takePicture = async () => { if (!camera) return const photo = await camera.takePictureAsync() }

First, we check that we have access to the Camera component using ref:

 if (!camera) return // if the camera is undefined or null, we stop the function execution

Then we take the picture by calling the takePictureAsync method. It returns a promise and an object that contains the picture's details. The result will look like this:

Object { "height": 4224, "uri": "file:///var/mobile/Containers/Data/Application/E6740A15-93AF-4120-BF11-6E8B74AFBF93/Library/Caches/ExponentExperienceData/%2540anonymous%252Fcamera-app-ee0fa3c8-1bb1-4d62-9863-33bf26341c55/Camera/19F0C5DD-7CA6-4043-8D89-AF65A1055C7E.jpg", "width": 1952, }

We are only interested in the Picture URL uri. After we take a picture, we have to show the photo preview and hide the camera view. To do that we will use two hooks to change the state:

 const [previewVisible, setPreviewVisible] = useState(false) const [capturedImage, setCapturedImage] = useState(null)
 const __takePicture = async () => { if (!camera) return const photo = await camera.takePictureAsync() console.log(photo) setPreviewVisible(true) setCapturedImage(photo) }
  • setPreviewVisible to show the preview
  • setCapturedImage(photo) to store the object result

Then we display the preview like this:

 {previewVisible && capturedImage ? (  ) : (  { camera = r }} >         )}

The CameraPreview component looks like this:

const CameraPreview = ({photo}: any) => { console.log('sdsfds', photo) return (    ) }

And the result looks like this:

How to re-take a picture

We can add some buttons to the preview that will allow the user to perform more actions. For example, they could re-take the photo or save it.

Add the savePhoto and retakePicture props to the CameraPreview component like this:

When the Re-take button is pressed, we will have to hide the preview, remove the current picture, and show the camera again. Do that with the following code:

 const __retakePicture = () => { setCapturedImage(null) setPreviewVisible(false) __startCamera() }

How to add other options – back camera, flash, and more

expo-camra offers many options for customizing the camera, like FlashMode, setting the Camera type (front/back), zooming, and so on.

How to add FlashMode

Let's add an option so the user can turn FlashMode on and off:

We simply create a small button to switch off/on the flash, like this:

   ⚡️  

And we just change the state when the button is pressed:

 const [flashMode, setFlashMode] = React.useState('off') const __handleFlashMode = () => { if (flashMode === 'on') { setFlashMode('off') } else if (flashMode === 'off') { setFlashMode('on') } else { setFlashMode('auto') } }

And then we add FlashMode props:

  { camera = r }} >

How to access the front and the back camera

We will add a button that switches between the back and front camera.

We can get the default camera type directly from the camera module like below:

 const [cameraType, setCameraType] = React.useState(Camera.Constants.Type.back)

Add type props like this:

  { camera = r }} >

And add the switch button:

  {cameraType === 'front' ? '?' : '?'}  

And switch function:

 const __switchCamera = () => { if (cameraType === 'back') { setCameraType('front') } else { setCameraType('back') } }

Here is the result:

You can find the full source code on GitHub.

Wrapping up

In general, Expo is an amazing tool that can save you a lot of time. It helps you start building directly and saves you the pain of environment setup.

A veces, es posible que desee crear una extensión nativa y manejar el uso de funciones nativas a su manera. En este caso, recomendaría usar la CLI nativa de reacción para que pueda modificar y jugar con el código nativo fácilmente.

Hola, mi nombre es Said Hayani. Creé subscribi.io para ayudar a creadores, bloggers e influencers a hacer crecer su audiencia a través del boletín.

Únase a mi lista de correo si está interesado en leer más sobre React Native.