TakePhoto.js

김종민·2022년 6월 9일
0

insta-native

목록 보기
26/36

npm install expo-media-library
npm install expo-camera
npm install @react-native-community/slider --save

https://docs.expo.dev/versions/v45.0.0/sdk/camera/

https://docs.expo.dev/versions/v45.0.0/sdk/camera/#props

https://docs.expo.dev/versions/v45.0.0/sdk/camera/#type

github.com/callstack/react-native-slider


~~안드로이드에서 카메라가 한번만 load될 경우(17.9)

import {useIsFocused} from '@react-navigation/native'

export const CameraView = (props) => {
const isFocused = useIsFocused();
return(

{isFocused &&}

)}~~
isFocused는 화면을 열었을떄 Focused되어 있는지를 확인해서 다음 부분 실행
isFocused ? 'camera 페이지 작동' : 'camera 페이지 않작동' <---내가 화면을 열었을때만 카메라가 작동하게
안그러면 카메라가 계속 작동하고 있어서 밧데리낭비가됨.

비율조절 ratio="16:9"


1. screens/takePhoto.js

import { Camera } from 'expo-camera'  ///1)expo-camera에서 Camera import!!
import React, { useEffect, useRef, useState } from 'react'
import {
  Alert,
  Image,
  StatusBar,
  Text,
  TouchableOpacity,
  View,
} from 'react-native'
import styled from 'styled-components/native'
import Slider from '@react-native-community/slider' ///3) zoom에 사용할 Slider import!!
import * as MediaLibrary from 'expo-media-library' ///2)MediaLibrary import!!
import { Ionicons } from '@expo/vector-icons'

const Container = styled.View`
  flex: 1;
  background-color: black;
`
const Actions = styled.View`
  flex: 0.3;
  padding: 0px 50px;
  align-items: center;
  justify-content: space-around;
`
const ButtonsContainer = styled.View`
  width: 100%;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
`

const TakePhotoBtn = styled.TouchableOpacity`
  width: 100px;
  height: 100px;
  background-color: white;
  border: 2px solid rgba(255, 255, 255, 0.8);
  border-radius: 50px;
`

const SlideContainer = styled.View``
const ActionsContainer = styled.View`
  flex-direction: row;
`

const CloseButton = styled.TouchableOpacity`
  position: absolute;
  top: 50px;
  left: 50px;
`
const PhotoAction = styled.TouchableOpacity`
  background-color: white;
  padding: 5px 10px;
  border-radius: 5px;
`
const PhotoActionText = styled.Text`
  font-weight: 600;
`

export default function TakePhoto({ navigation }) {
  const camera = useRef()  
  ///4)camera를 useRef로 잡아주고 return의 <Camera />에 넣어줌.
  
  const [takenPhoto, setTakenPhoto] = useState('')  ///사진찍고 담아줄 state
  const [cameraReady, setCameraReady] = useState(false)  
  ///camera사용시 무조건 넣어주어야 할 state
  
  const [ok, setOk] = useState(false) ///permission과 관련된 state
  const [zoom, setZoom] = useState(0)  ///zoom과 관련된 state
  const [flashMode, setFlashMode] = useState(Camera.Constants.FlashMode.off)
  ///카메라 Flash와 관련된 state, default는 off
  
  const [cameraType, setCameraType] = useState(Camera.Constants.Type.back)
  //카메라가 전면인지, 후면인지, 잡아주는 state, default는 back
  
  const getPermissions = async () => {
    const { granted } = await Camera.requestCameraPermissionsAsync()
    setOk(granted)
  }
  ///5)카메라 사용 permission을 request하는 함수. granted의 state는 boolean이라서
  ///setok에 granted를 넣어줌.
  
  useEffect(() => {
    getPermissions()
  }, [])
  ///6)화면이 rendering될 때, getPermissions()함수 바로 실행되게 함.
  
  const onCameraSwitch = () => {
    if (cameraType === Camera.Constants.Type.front) {
      setCameraType(Camera.Constants.Type.back)
    } else {
      setCameraType(Camera.Constants.Type.front)
    }
  }
  const onZoomValueChange = (e) => {
    setZoom(e)
  }
  ///7)cameraSwitch가 앞, 뒤 바뀌게 하는 함수, 
  ///return부분의 camera위치변경 버튼에 함수를 onPress에 연결시킨다.
  
  const onFlashChange = () => {
    if (flashMode === Camera.Constants.FlashMode.off) {
      setFlashMode(Camera.Constants.FlashMode.on)
    } else if (flashMode === Camera.Constants.FlashMode.on) {
      setFlashMode(Camera.Constants.FlashMode.auto)
    } else if (flashMode === Camera.Constants.FlashMode.auto) {
      setFlashMode(Camera.Constants.FlashMode.off)
    }
  }
  ///8)flash 켜고, 꺼고, 오토로 하는 함수. 
  ///return부분의 flash변경 버튼에 onPress로 연결한다.
  
  const goToUpload = async (save) => {
    if (save) {
      await MediaLibrary.createAssetAsync(takenPhoto)
      ///찍은 사진을 폰에 저장하는데, 값을 return받고 싶을떄는,
      ///createAssetAsync(takenPhoto)사용
      
      //save한 값을 return받지 않아도 될 떄는.
      // await MediaLibrary.saveToLibraryAsync(takePhoto)
    }
    navigation.navigate('UploadForm', {
      file: takenPhoto,
    })
  }
  ///22)밑의 onUpload함수의 Alert버튼의 선택여부에 따라( if(save{~~~~~})
  ///함수 실행 여부 결정됨.
  /// 저장 후 UploadForm page로 갈것인지, 저장 안하고 UploadForm page로 갈것인지 여부
  /// 어떤 경우이든 Upload는 해야 되니까, props로 file(key)에 takenPhoto(value)를
  /// 넣어서 보내준다.
  
  const onUpload = () => {
    Alert.alert('Save Photo?', 'Save Photo & upload or just upload', [
    	///첫번째('Save Photo?'는 제목, 두번째는 제목밑의 설명)
    
      {
        text: 'Save & Upload',
        onPress: () => goToUpload(true),  ///폰에 사진을 저장 후 Upload
      },
      {
        text: 'Just Upload',
        onPress: () => goToUpload(false),  ///폰에 사진 저장없이 Upload.
      },
    ])
  }
  ///21)사진을 찍은 후, Upload버튼을 눌렀을 때, 실행되는 함수.
  ///Alert(from react-native)를 사용해서, 두개의 버튼을 만들어줌.
  ///goToUpload함수를 true로 실행시킬지, false로 실행시킬지 여부를 선택하게 함.
  ///react-native의 Alert는 callback(함수 안에 함수)함수로 버턴 선택시,
  ///함수 실행되게 함.
  
  const onCameraReady = () => setCameraReady(true)
  ///9)공식문서에 따라 무조건 만들어주어야 되는 함수.
  /// return부분의 <Camera />에 연결해준다.
  
  const takePhoto = async () => {
    if (camera.current && cameraReady) {
    	///18)camera가 current이고(ref로 설정해줬음), cameraReadt가
        ///true이면 
    
      const { uri } = await camera.current.takePictureAsync({
        quality: 1,
        exif: true,
      })
      ///19)takePictureAsync()로 사진을 찍음.
      /// const photo = await camera.current.takePictureAsync()
      /// console.log(photo)를 하면, 찍은 사진에 대한 정보를 확인 가능함.
      ///우리는 사진의 uri만 필요해서 const {uri} =~~~ 로 코딩함.
      /// quality는 사진 퀄리리 값은 0~1 사이임.
      /// exif는 사진의 대한 메타정보(사진찍은 위치등등)를 받을것인지 여부
      /// takePictureAsync()의 옵션은 매우 많으니 공식문서를 보고
      /// 다양한 option을 적용시켜 보아야함.
      
      
      setTakenPhoto(uri)
      ///20) 찍은 사진의 uri를 setTakenPicture에 담아줌.
      ///사진을 찍고 나면, takenPhoto가  '' 이 아니라,
      ///dismiss, upload두개의 버튼이 나오게 됨. 어느것누르냐에 따라, 
      ///다른 함수(onDismiss, onUpload)가 실행되게 됨.
      
      // const asset = await MediaLibrary.createAssetAsync(uri)
      // 위와 값이 하면, 찍은 사진을 나의 폰에 저장할 수 있음.
      ///메서드는 createAssetAsync()임. variables는 위에서 받은 uri
      ///찍는다고 바로 저장되는게 아님.
    }
  }
  const onDismiss = () => setTakenPhoto('')
  /// onDismiss버튼을 눌렀을 떄, setTakenPhoto를 비워서 다시 사진을 찍게 만든는 함수.
  
  return (
    <Container>
      <StatusBar hidden={true} />
      {takenPhoto === '' ? (
        <Camera
          type={cameraType}      ===>useState로 잡아준 값
          style={{ flex: 1 }}
          zoom={zoom}            ===>useState로 잡아준 값
          flashMode={flashMode}  ===>useState로 잡아준 값
          ref={camera}
          onCameraReady={onCameraReady} ===>useState로 잡아준 값
        >
          <CloseButton onPress={() => navigation.navigate('Tabs')}>
            <Ionicons name="close" color="white" size={35} />
          </CloseButton>
        </Camera>
        ///10) <Camera />안에 들어가는 props들을 집중!집중해서 볼것.
        ///type, style, zoom, flashMode, ref, onCameraReady는
        ///무조건 문법에 따라 넣어줄 것.
        ///close버튼은 position:absolute로 이 버튼을 누르면, Tabs Nav로 이동시킨다.
        
      ) : (
        <Image source={{ uri: takenPhoto }} style={{ flex: 1 }} />
        ///11)takenPhoto가 ''이 아닐경우, 찍힌 사진을 화면에 띄운다.
        
      )}
      {takenPhoto === '' ? (
        <Actions>
          <SlideContainer>
            <Slider
              style={{ width: 200, height: 40 }}
              minimumValue={0}
              maximumValue={1}
              minimumTrackTintColor="#FFFFFF"
              maximumTrackTintColor="rgba(255,255,255,0.5)"
              onValueChange={onZoomValueChange}
            />
          </SlideContainer>
          ///12)Slider Bar를 이용해서 zoom의 state 변화와 연결시킨다.
          ///onZoomValueChange 함수를 만들어 onValueChange에 넣어준다.
          
          <ButtonsContainer>
            <TakePhotoBtn onPress={takePhoto} />
            ///17)가장 중요한 찰칵 버튼을 눌렀을떄, takePhoto함수가 실행되게 함.
            ///takePhoto함수 만드는 부분으로 넘어갈 것.
            ///이 POST에서 가장 중요한 부분.
            
            <ActionsContainer>
              <TouchableOpacity
                onPress={onFlashChange}
                style={{ marginRight: 30 }}
              >
                <Ionicons
                  color="white"
                  size={30}
                  name={
                    flashMode === Camera.Constants.FlashMode.off
                      ? 'flash-off'
                      : flashMode === Camera.Constants.FlashMode.on
                      ? 'flash'
                      : flashMode === Camera.Constants.FlashMode.auto
                      ? 'eye'
                      : null
                  }
                />
              </TouchableOpacity>
              ///13)flash를 off, on, auto로 변경시키는 버튼을 만든다.
              ///onPress에는 위에서 만든 onFlashChange함수를 연결한다.
              
              <TouchableOpacity onPress={onCameraSwitch}>
                <Ionicons
                  color="white"
                  size={30}
                  name={
                    cameraType === Camera.Constants.Type.front
                      ? 'camera-reverse'
                      : 'camera'
                  }
                />
              </TouchableOpacity>
              ///14)카메라가 back인지, front인지 바꿔주는 버튼.
              ///onPress에 onCameraSwitch함수를 연결한다.
              
            </ActionsContainer>
          </ButtonsContainer>
        </Actions>
      ) : (
      ///15)사진을 찍었을떄, takenPhoto가 ''이 아닐때 보여줄 화면.
      
        <Actions>
          <PhotoAction onPress={onDismiss}> 
            <PhotoActionText>Dismiss</PhotoActionText>
          </PhotoAction>
          <PhotoAction onPress={onUpload}>
            <PhotoActionText>Upload</PhotoActionText>
          </PhotoAction>
        </Actions>
        ///16)onDismiss버튼은 사진다시찍기, Upload버튼은 사진을 업로드 할 버튼.
        ///onDismiss 함수와, onUpload버튼은 위애서 만든다.
        
      )}
    </Container>
  )
}


사진부분은 options이 많아서 다루기 어려운 부분이다.
일단, 기본적인 부분은 위에서 설명이 되어있지만, 나아가 video를 다루는 부분이라든가,
찍은 후, 사진이 보여지는 비율, 방법, 크기, rotate 부분 등의 다양한 옵션은
반드시 시간을내어서 공부해 볼것!
video부분 또한 마찬가지임.

profile
코딩하는초딩쌤

0개의 댓글