Como criar um aplicativo de câmera com Expo e React Native


Se você não está familiarizado com Expo, é um cliente que ajuda você a construir aplicativos React Native com menos complexidade de construção. Também ajuda a lidar com o estresse de instalar e configurar seu ambiente para executar o React Native.

Neste tutorial, estaremos construindo um aplicativo de câmera simples no qual o usuário pode tirar fotos, ver visualizações de suas fotos, usar o modo flash e alternar entre as câmeras frontal e traseira.

Pré-requisitos

Expo não exige muito para começar a construir seu primeiro aplicativo React Native. Você pode aprender mais sobre como instalar expo e o expo-cli aqui na documentação.

Observação: neste tutorial, estarei usando macOS e iOS. Você também pode usar o Android, não há muita diferença ao usar o Expo neste ponto.

Você pode instalar o expo e o expo-cli globalmente executando o seguinte comando:

npm install --global expo-cli

Expo requer Nodejs para funcionar. Você pode executar a versão mais recente no site oficial aqui.

Começando

Depois de instalar o Expo e o Nodejs, você pode iniciar a inicialização de um novo projeto Expo com o comando abaixo:

expo init expo-camera-app

Como instalar os pacotes e executar o aplicativo

A Expo nos fornece um aplicativo cliente onde podemos executar e ver uma prévia do aplicativo que estamos construindo. Está disponível em ambos Loja de aplicativos e Google Play baixar.

Esta é a interface do aplicativo.

Como iniciar um projeto expo

Vá para o diretório do aplicativo e execute o aplicativo.

cd expo-camera-app

Serão feitas algumas perguntas para selecionar o modelo padrão para o aplicativo. Neste tutorial, simplesmente selecionamos uma opção em branco (TypeScript), mas, novamente, você é livre para escolher o que é certo para você.

Execute o aplicativo

Depois de inicializar o projeto, podemos executar o aplicativo com expo run

Isso abrirá uma janela em seu navegador onde você pode ver os logs. Ele também irá gerar um código QR que você pode escanear para executar o aplicativo em seu dispositivo.

O bom do expo é que você não precisa instalar e configurar os simuladores para executar o aplicativo. Ele ainda oferece a opção de executar o expo no simulador, mas você deve instalar e configurar o simulador sozinho.

De volta ao nosso aplicativo. Supondo que você tenha executado com êxito o aplicativo no dispositivo, esta será a tela padrão:

Abra o diretório do aplicativo em seu editor de código favorito. estou a usar Código VS.

o App.tsx será parecido com isto:

import {StatusBar} from 'expo-status-bar'
import React from 'react'
import {StyleSheet, Text, View} from 'react-native'

export default function App() {
  return (
    <View style={styles.container}>
      <Text>Open up App.tsx to start working on your app!</Text>
      <StatusBar style="auto" />
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center'
  }
})

Como criar a IU

Depois de ter o projeto em execução, agora é hora de começar a criar alguma IU.

Instalar expo-camera

A próxima etapa é instalar câmera de exposição, como isso:

expo install expo-camera

Vamos criar uma interface de usuário simples que permitirá ao usuário iniciar o processo de uso da câmera.

import {StatusBar} from 'expo-status-bar'
import React from 'react'
import {StyleSheet, Text, View, TouchableOpacity} from 'react-native'

export default function App() {
  return (
    <View style={styles.container}>
      <View
        style={{
          flex: 1,
          backgroundColor: '#fff',
          justifyContent: 'center',
          alignItems: 'center'
        }}
      >
        <TouchableOpacity
          style={{
            width: 130,
            borderRadius: 4,
            backgroundColor: '#14274e',
            flexDirection: 'row',
            justifyContent: 'center',
            alignItems: 'center',
            height: 40
          }}
        >
          <Text
            style={{
              color: '#fff',
              fontWeight: 'bold',
              textAlign: 'center'
            }}
          >
            Take picture
          </Text>
        </TouchableOpacity>
      </View>

      <StatusBar style="auto" />
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center'
  }
})

É uma IU simples: importamos TouchableOpacity para o botão e faça um estilo simples. Se você está se perguntando como o estilo funciona no React Native, você pode verificar meus dois artigos aqui:

Agora temos que usar um useState gancho para gerenciar o estado e exibir a visão da câmera quando o usuário pressiona o tire uma foto botão.

  <TouchableOpacity
        onPress={__startCamera}
          style={{
            width: 130,
            borderRadius: 4,
            backgroundColor: '#14274e',
            flexDirection: 'row',
            justifyContent: 'center',
            alignItems: 'center',
            height: 40
          }}
        >
          <Text
            style={{
              color: '#fff',
              fontWeight: 'bold',
              textAlign: 'center'
            }}
          >
            Take picture
          </Text>
        </TouchableOpacity>

  const [startCamera,setStartCamera] = React.useState(false)

const __startCamera = ()=>{

}

Há duas coisas importantes que devemos fazer quando o usuário pressiona o botão:

  • Peça permissão para acessar a câmera. No desenvolvimento móvel, o acesso a muitas APIs nativas e recursos móveis é frequentemente restrito pelas permissões e privacidade do usuário. É apenas algo com o qual você precisa se acostumar ao desenvolver aplicativos móveis.
  • Mude o estado e apresente a câmera.

Vamos importar o módulo da câmera de expo-camera com este comando:

import {Camera} from 'expo-camera'

E adicione a visão da câmera, assim:

    <Camera
    style={{flex: 1,width:"100%"}}
    ref={(r) => {
    camera = r
    }}
    ></Camera>

Podemos usar ref para acessar os métodos da câmera:

let camera: Camera

Quando o take picture botão é pressionado o __startCamera função será chamada:

  const __startCamera = async () => {
    const {status} = await Camera.requestPermissionsAsync()
 if(status === 'granted'){
   // do something

 }else{
   Alert.alert("Access denied")
 }

A função pedirá permissão primeiro. Se o usuário conceder acesso à câmera, podemos prosseguir e abrir a câmera. Caso contrário, mostramos um alerta simples.

Adicione o componente da câmera

Vamos exibir a câmera quando o usuário conceder acesso à câmera do dispositivo.

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

Temos que fazer algumas mudanças na IU e adicionar uma renderização condicional. Exibimos a câmera apenas quando o usuário solicita, caso contrário exibimos a tela padrão.

  {startCamera ? (
        <Camera
          style={{flex: 1,width:"100%"}}
          ref={(r) => {
            camera = r
          }}
        ></Camera>
      ) : (
        <View
          style={{
            flex: 1,
            backgroundColor: '#fff',
            justifyContent: 'center',
            alignItems: 'center'
          }}
        >
          <TouchableOpacity
            onPress={__startCamera}
            style={{
              width: 130,
              borderRadius: 4,
              backgroundColor: '#14274e',
              flexDirection: 'row',
              justifyContent: 'center',
              alignItems: 'center',
              height: 40
            }}
          >
            <Text
              style={{
                color: '#fff',
                fontWeight: 'bold',
                textAlign: 'center'
              }}
            >
              Take picture
            </Text>
          </TouchableOpacity>
        </View>
      )}

Legal, agora precisamos adicionar um botão para que possamos tirar a foto real.

Adicione o botão de captura

Este é um simples View dentro da visão da câmera que tem uma posição absoluta. Por isso, certificamo-nos de que está sempre na parte superior da câmera.

    <View
        style={{
        position: 'absolute',
        bottom: 0,
        flexDirection: 'row',
        flex: 1,
        width: '100%',
        padding: 20,
        justifyContent: 'space-between'
        }}
      >
        <View
        style={{
        alignSelf: 'center',
        flex: 1,
        alignItems: 'center'
        }}
        >
            <TouchableOpacity
            onPress={__takePicture}
            style={{
            width: 70,
            height: 70,
            bottom: 0,
            borderRadius: 50,
            backgroundColor: '#fff'
            }}
            />
    </View>
    </View>

Como tirar uma foto

O aplicativo deve tirar uma foto quando o botão de captura é pressionado. Essa função será semelhante a esta:

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

Primeiro, verificamos se temos acesso ao Camera componente usando ref:

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

Então tiramos a foto chamando o takePictureAsync método. Ele retorna uma promessa e um objeto que contém os detalhes da imagem. O resultado será assim:

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,
}

Estamos interessados ​​apenas no URL da imagem uri. Depois de tirar uma foto, temos que mostrar a visualização da foto e ocultar a visão da câmera. Para fazer isso, usaremos dois ganchos para alterar o estado:

  const [previewVisible, setPreviewVisible] = useState(false)
  const [capturedImage, setCapturedImage] = useState<any>(null)

  const __takePicture = async () => {
    if (!camera) return
    const photo = await camera.takePictureAsync()
    console.log(photo)
    setPreviewVisible(true)
    setCapturedImage(photo)
  }

  • setPreviewVisible para mostrar a prévia
  • setCapturedImage(photo) para armazenar o resultado do objeto

Em seguida, exibimos a visualização assim:

  {previewVisible && capturedImage ? (
            <CameraPreview photo={capturedImage} />
          ) : (
            <Camera
              style={{flex: 1}}
              ref={(r) => {
                camera = r
              }}
            >
              <View
                style={{
                  flex: 1,
                  width: '100%',
                  backgroundColor: 'transparent',
                  flexDirection: 'row'
                }}
              >
                <View
                  style={{
                    position: 'absolute',
                    bottom: 0,
                    flexDirection: 'row',
                    flex: 1,
                    width: '100%',
                    padding: 20,
                    justifyContent: 'space-between'
                  }}
                >
                  <View
                    style={{
                      alignSelf: 'center',
                      flex: 1,
                      alignItems: 'center'
                    }}
                  >
                    <TouchableOpacity
                      onPress={__takePicture}
                      style={{
                        width: 70,
                        height: 70,
                        bottom: 0,
                        borderRadius: 50,
                        backgroundColor: '#fff'
                      }}
                    />
                  </View>
                </View>
              </View>
            </Camera>
          )}

o CameraPreview componente tem a seguinte aparência:

const CameraPreview = ({photo}: any) => {
  console.log('sdsfds', photo)
  return (
    <View
      style={{
        backgroundColor: 'transparent',
        flex: 1,
        width: '100%',
        height: '100%'
      }}
    >
      <ImageBackground
        source={{uri: photo && photo.uri}}
        style={{
          flex: 1
        }}
      />
    </View>
  )
}

E o resultado é o seguinte:

Como tirar uma foto novamente

Podemos adicionar alguns botões à visualização que permitirão ao usuário realizar mais ações. Por exemplo, eles podem tirar a foto novamente ou salvá-la.

Adicione o savePhoto e retakePicture adereços para o CameraPreview componente como este:

<CameraPreview photo={capturedImage} savePhoto={__savePhoto} retakePicture={__retakePicture} />

Quando o Re-take for pressionado, teremos que ocultar a visualização, remover a imagem atual e mostrar a câmera novamente. Faça isso com o seguinte código:

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

Como adicionar outras opções – câmera traseira, flash e mais

Expo-camra oferece muitas opções para personalizar a câmera, como FlashMode, definir o tipo de câmera (frente / trás), zoom e assim por diante.

Como adicionar FlashMode

Vamos adicionar uma opção para que o usuário possa ligar e desligar FlashMode:

Simplesmente criamos um pequeno botão para desligar / ligar o flash, como este:

        <TouchableOpacity
            onPress={__handleFlashMode}
            style={{
            position: 'absolute',
            left: '5%',
            top: '10%',
            backgroundColor: flashMode === 'off' ? '#000' : '#fff',
            borderRadius: '50%',
            height: 25,
            width: 25
        }}
        >
            <Text
                style={{
                fontSize: 20
                }}
            >
            ⚡️
            </Text>
        </TouchableOpacity>

E apenas mudamos o estado quando o botão é pressionado:

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

  }

E então adicionamos adereços FlashMode:

    <Camera
    flashMode={flashMode}
    style={{flex: 1}}
    ref={(r) => {
    camera = r
    }}
    ></Camera>

Como acessar a câmera frontal e traseira

Vamos adicionar um botão que alterna entre a câmera traseira e frontal.

Podemos obter o tipo de câmera padrão diretamente do módulo da câmera como abaixo:

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

Adicionar type adereços como este:

    <Camera
    type={cameraType}
    flashMode={flashMode}
    style={{flex: 1}}
    ref={(r) => {
    camera = r
    }}
    ></Camera>

E adicione o botão de troca:

<TouchableOpacity
    onPress={__switchCamera}
    style={{
    marginTop: 20,
    borderRadius: '50%',
    height: 25,
    width: 25
    }}
   >
       <Text
           style={{
           fontSize: 20
           }}
           >
       {cameraType === 'front' ? '🤳' : '📷'}
       </Text>
</TouchableOpacity>

E mudar a função:

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

Aqui está o resultado:

Você pode encontrar o código-fonte completo em GitHub.

Empacotando

Em geral, Expo é uma ferramenta incrível que pode economizar muito tempo. Ele ajuda você a começar a construir diretamente e evita o trabalho de configuração do ambiente.

Às vezes, você pode querer construir uma extensão nativa e lidar com o uso de recursos nativos de sua própria maneira. Neste caso, eu recomendo usar o reagir nativo CLI para que você possa modificar e brincar com o código nativo facilmente.

Olá, meu nome é Said Hayani. eu criei subscribi.io para ajudar criadores, blogueiros e influenciadores a aumentar seu público por meio do boletim informativo.

Junte-se ao meu Lista de correio se você estiver interessado em ler mais sobre React Native.



Fonte

Leave a Reply

Your email address will not be published. Required fields are marked *