
Parte 1
Parte 2
Parte 3
Primeiro Passo
Instalar Expo Camera no nosso projeto.
1 |
expo install expo-camera expo-contacts expo-sensors |
Importar SafeAreaView e inserir SafeAreaView para que no ios fique abaixo dos icons.
1 2 |
<SafeAreaView> </SafeAreaView> |
Vamos criar uma pasta src e dentro dela o style.js. Dentro do style vamos colocar nosso style e depois importar o style no nosso app.js.
1 2 3 4 5 6 7 8 |
const styles = StyleSheet.create({ container: { flex: 1, justifyContent: "center", }, }); export default styles |
Já podemos importar nossa câmera.
1 |
import { Camera } from 'expo-camera'; |
Vamos criar um state para trazer por padrão nossa camera traseira.
1 |
const [type, setType] = useState(Camera.Constants.Type.back); |
Agora já podemos inserir nossa câmera no return do nosso app.
1 |
<Camera style={styles.camera} type={type} > |
E criar o style da nossa camera.
1 2 3 4 |
camera:{ width:"100%", height:"100%", } |
Antes de Salvar e utilizar, vamos criar as permissões do usuário. Vamos começar criando o state que irá armazenar a permissão.
1 |
const [hasPermission, setHasPermission] = useState(null); |
Vamos também preparar o nosso ciclo de vida do nosso componente com useEfect. Começando importando do React o useEfect.
1 |
import React, { useState, useEffect } from "react"; |
Vamos iniciar ouseEfect:
1 2 3 |
useEfect(() =>{ }, []); |
Vamos então dentro do nosso use efect criar uma função assyncrona que vai pegar o status e setar a permission.
1 2 3 4 5 6 |
useEffect(() => { (async () => { const { status } = await Camera.requestPermissionsAsync(); setHasPermission(status === "granted"); })(); }, []); |
Agora precisamos fazer algumas verificações, pois caso a Permission for igual a vazio ou null, não poderemos permitir.
1 2 3 4 5 6 |
if (hasPermission === null) { return <View />; } if (hasPermission === false) { return <Text>No access to camera</Text>; } |
Agora vamos seguir implementando dois botões: o flip para poder virar a camera e um botão para tirar a foto. Vamos começar criando uma view onde ficarão nossos botões.
1 2 3 4 |
<Camera>... <View style={styles.contentButtons}> </View> ...</Camera> |
Vamos adicionar o style.
1 2 3 4 5 |
contentButtons: { flex: 1, backgroundColor: "transparent", flexDirection: "row", }, |
Nosso primeiro botão dentro de contentButtons vai ser o de alternar entre as câmeras.
1 2 3 4 5 6 7 8 9 10 11 12 |
<TouchableOpacity style={styles.buttonFlip} onPress={() => { setType( type === Camera.Constants.Type.back ? Camera.Constants.Type.front : Camera.Constants.Type.back ); }} > <FontAwesome name="exchange" size={23} color="red"></FontAwesome> </TouchableOpacity> |
Vamos utilizar o FontAwesome que já é padrão do expo. Para isso devemos importá-lo.
1 |
import { FontAwesome } from "@expo/vector-icons"; |
E o style do nosso botão de flip fica assim:
1 2 3 4 5 6 7 8 9 10 11 12 |
buttonFlip: { position: "absolute", bottom: 50, left: 30, justifyContent: "center", alignItems: "center", backgroundColor: "#fff", margin: 20, height: 50, width: 50, borderRadius: 50, }, |
Com nosso botão de flip implementado podemos alternar entre a câmera traseira e câmera frontal sem problemas.
Nosso próximo passo é implementar o botão que tira fotos.
Para isso iremos utilizar aqui o useRef do React que irá nos ajudar a armazenar uma referência para um caso muito especifico que irá de fazer uma chamada async para pegar o url da foto.
Vamos então importar o useRef.
1 |
import React, { useState, useEffect, useRef } from "react"; |
E depois criar acima dos states criados.
1 2 3 4 |
... export default function App() { const camRef = useRef(null);// adicionando useRef const [hasPermission, setHasPermission] = useState(null); ... |
Vamos criar um state que irá receber a url da foto tirada.
1 |
const [capturedPhoto, setCapturedPhoto] = useState(null); |
Então vamos criar uma chamada async para quando tirar a foto.
1 2 3 4 5 6 7 |
async function takePicture() { if (camRef) { const data = await camRef.current.takePictureAsync(); setCapturedPhoto(data.uri); //console.log(data); } } |
Logo após nosso botão de flip, vamos criar o botão de tirar foto.
1 2 3 |
<TouchableOpacity style={styles.buttonCamera} onPress={takePicture}> <FontAwesome name="camera" size={23} color="#fff"></FontAwesome> </TouchableOpacity> |
Vamos estilizar nosso botão da câmera.
1 2 3 4 5 6 7 8 9 10 11 12 |
buttonCamera: { position: "absolute", bottom: 50, right: 30, justifyContent: "center", alignItems: "center", backgroundColor: "red", margin: 20, height: 50, width: 50, borderRadius: 50, }, |
Agora que já estamos alternando entre as câmeras, tirando foto e imprimindo no console, vamos exibir nossas images.
Vamos utilizar um modal do próprio reactNative.
Precisamos importar do “react-native” o modal.
1 2 3 4 5 6 7 8 9 |
import { Text, View, Image, Modal,//adicionar modal TouchableOpacity, SafeAreaView, StyleSheet, } from "react-native"; |
Vamos criar um state para abrir e fechar o modal.
1 |
const [open, setOpen] = useState(false); |
E na função onde estamos pegando a url da imagem vamos dar um setOpen(true).
1 2 3 4 5 6 7 8 |
async function takePicture() { if (camRef) { const data = await camRef.current.takePictureAsync(); setCapturedPhoto(data.uri); setOpen(true); //console.log(data); } } |
Construindo nosso Modal
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{capturedPhoto && ( <Modal animationType="slide" transparent={true} visible={open}> <View style={styles.contentModal}> <TouchableOpacity style={styles.closeButton} onPress={() => setOpen(false)} > <FontAwesome name="close" size={50} color="#fff"></FontAwesome> </TouchableOpacity> <Image style={styles.imgPhoto} source={{ uri: capturedPhoto }} /> </View> </Modal> )} |
O estilo de content Modal fica assim.
1 2 3 4 5 6 |
contentModal:{ flex: 1, justifyContent: "center", alignItems: "flex-end", margin: 20, }, |
O estilo de closeButton ficará assim.
1 2 3 4 5 6 |
closeButton: { position: "absolute", top: 10, left: 2, margin: 10 } |
O estilo da nossa imagem ficará assim.
1 2 3 4 |
imgPhoto: { width: "100%", height: 400, } |
E assim Finalizamos nosso App onde conseguimos tirar uma foto, alternar entre as câmeras e visualizar nossa foto em um modal!
Código Completo Final
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 77 78 79 80 |
import React, { useState, useEffect, useRef } from "react"; import { Text, View, Image, Modal, TouchableOpacity, SafeAreaView, } from "react-native"; import styles from "./src/style" import { Camera } from "expo-camera"; import { FontAwesome } from "@expo/vector-icons"; export default function App() { const camRef = useRef(null); const [hasPermission, setHasPermission] = useState(null); const [type, setType] = useState(Camera.Constants.Type.back); const [capturedPhoto, setCapturedPhoto] = useState(null); const [open, setOpen] = useState(false); useEffect(() => { (async () => { const { status } = await Camera.requestPermissionsAsync(); setHasPermission(status === "granted"); })(); }, []); if (hasPermission === null) { return <View />; } if (hasPermission === false) { return <Text>No access to camera</Text>; } async function takePicture() { if (camRef) { const data = await camRef.current.takePictureAsync(); setCapturedPhoto(data.uri); setOpen(true); //console.log(data); } } return ( <SafeAreaView style={styles.container}> <Camera style={styles.camera} type={type} ref={camRef}> <View style={styles.contentButtons}> <TouchableOpacity style={styles.buttonFlip} onPress={() => { setType( type === Camera.Constants.Type.back ? Camera.Constants.Type.front : Camera.Constants.Type.back ); }} > <FontAwesome name="exchange" size={23} color="red"></FontAwesome> </TouchableOpacity> <TouchableOpacity style={styles.buttonCamera} onPress={takePicture}> <FontAwesome name="camera" size={23} color="#fff"></FontAwesome> </TouchableOpacity> </View> </Camera> {capturedPhoto && ( <Modal animationType="slide" transparent={true} visible={open}> <View style={styles.contentModal}> <TouchableOpacity style={styles.closeButton} onPress={() => setOpen(false)} > <FontAwesome name="close" size={50} color="#fff"></FontAwesome> </TouchableOpacity> <Image style={styles.imgPhoto} source={{ uri: capturedPhoto }} /> </View> </Modal> )} </SafeAreaView> ); } |
style.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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
import { StyleSheet } from "react-native" const styles = StyleSheet.create({ container: { flex: 1, justifyContent: "center", }, camera: { height: "100%", width: "100%", }, contentButtons: { flex: 1, backgroundColor: "transparent", flexDirection: "row", }, buttonCamera: { position: "absolute", bottom: 50, right: 30, justifyContent: "center", alignItems: "center", backgroundColor: "red", margin: 20, height: 50, width: 50, borderRadius: 50, }, buttonFlip: { position: "absolute", bottom: 50, left: 30, justifyContent: "center", alignItems: "center", backgroundColor: "#fff", margin: 20, height: 50, width: 50, borderRadius: 50, }, contentModal: { flex: 1, justifyContent: "center", alignItems: "flex-end", margin: 20, }, closeButton: { position: "absolute", top: 10, left: 2, margin: 10, }, imgPhoto: { width: "100%", height: 400, }, }); export default styles |
Espero que você tenha aprendido mais sobre como é possível trabalhar com câmera no React Native.
Te incentivo a ler a documentação e saber mais sobre como trabalhar com câmeras.
Se curtiu, entre no grupo do WhatsApp do Onebitcode sobre React Native e também se inscreva na lista de interessados em React Native clicando aqui para receber mais conteúdos e ser avisado assim que sair novos conteúdos aqui no canal!
Até a próxima aula!!!