Как да създадете приложение за камера с Expo и React Native

Ако не сте запознати с експо, това е клиент, който ви помага да създавате React Native приложения с по-малко сложност на изграждане. Той също така ви помага да се справите със стреса от инсталирането и настройката на вашата среда за стартиране на React Native.

В този урок ще създадем просто приложение за камера, в което потребителят може да прави снимки, да вижда визуализации на своите снимки, да използва режим на светкавица и да превключва между предната и задната камери.

Предпоставки

Expo не изисква много, за да започне изграждането на първото ви приложение React Native. Можете да научите повече за инсталирането на expo и expo-cli тук в документите.

Забележка: в този урок ще използвам macOS и iOS. Можете да използвате и Android, няма голяма разлика при използването на експо в този момент.

Можете да инсталирате expo и expo-cli глобално, като изпълните следната команда:

npm install --global expo-cli

Expo изисква Nodejs, за да стартира. Можете да стартирате най-новата версия на официалния уебсайт тук.

Приготвяме се да започнем

След като инсталирате Expo и Nodejs, можете да започнете да зареждате нов проект на Expo с командата по-долу:

expo init expo-camera-app

Как да инсталирате пакетите и да стартирате приложението

Expo ни предоставя клиентско приложение, където можем да стартираме и да видим визуализацията на приложението, което изграждаме. Налице е от App Store и Google Play за изтегляне.

Това е интерфейсът на приложението.

Как да започнете експо проект

Отидете в директорията на приложението и стартирайте приложението.

cd expo-camera-app 

Ще ви бъдат зададени няколко въпроса, за да изберете шаблона по подразбиране за приложението. В този урок ние просто избираме празна опция (TypeScript), но отново можете да изберете какво е точно за вас.

Стартирайте приложението

След стартиране на проекта можем да стартираме приложението с expo run

Това ще отвори прозорец във вашия браузър, където можете да видите дневниците. Той също така ще генерира QR код, който можете да сканирате, за да стартирате приложението на вашето устройство.

Хубавото на expo е, че не е необходимо да инсталирате и конфигурирате симулаторите, за да стартирате приложението. Все още ви дава възможност да стартирате експо на симулатора, но трябва да инсталирате и конфигурирате симулатора сами.

Обратно към нашето приложение. Ако приемем, че сте стартирали успешно приложението на устройството, това ще бъде екранът по подразбиране:

Отворете директорията на приложението в любимия си редактор на код. Използвам VS код.

The App.tsxще изглежда така:

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' } }) 

Как да създам потребителски интерфейс

След стартиране на проекта, сега е време да започнете да създавате потребителски интерфейс.

Инсталирайте експо-камера

Следващата стъпка е да инсталирате expo-камера, като тази:

expo install expo-camera

Ще създадем прост потребителски интерфейс, който ще позволи на потребителя да започне процеса на използване на камерата.

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' } }) 

Това е прост потребителски интерфейс: ние импортираме TouchableOpacityза бутона и правим няколко прости оформяния. Ако се чудите как работи стилът в React Native, можете да разгледате двете ми статии тук:

  • Стил в React Native
  • Демистифициране на Flexbox в React Native

Сега ние трябва да се използва useStateкука да управляват държавата и показва изгледа на камерата, когато потребител натиснете Снимай бутона.

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

Има две важни неща, които трябва да направим, когато потребителят натисне бутона:

  • Поискайте разрешение за достъп до камерата. При разработката на мобилни устройства достъпът до много собствени API и мобилни функции често е ограничен от разрешенията на потребителя и поверителността. Това е просто нещо, с което трябва да свикнете, когато разработвате мобилни приложения.
  • 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.

Понякога може да искате да създадете собствено разширение и да се справите с използването на собствени функции по свой собствен начин. В този случай бих препоръчал да използвате реагиращия CLI, за да можете лесно да променяте и играете с родния код.

Здравейте, казвам се Саид Хаяни. Създадох subsbi.io, за да помогна на създателите, блогърите и инфлуенсърите да разширят своята аудитория чрез бюлетина.

Присъединете се към моя пощенски списък, ако искате да прочетете повече за React Native.