React Native 中如何使用手机摄像头拍照并获取数据

Posted

技术标签:

【中文标题】React Native 中如何使用手机摄像头拍照并获取数据【英文标题】:How to take a picture and get the data in React Native with the mobile camera 【发布时间】:2018-08-25 18:24:19 【问题描述】:

在你说这是重复之前,让我解释一下。 我知道如何在 React Native 中使用 Camera,但是上个月在 android(Java) 中我以一种简单的方式管理设备摄像头,我什至不必创建一个新的 View 来使用它。我只是做了这样的事情:

Uri mOutputFileUri;
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mOutputFileUri); // URI of the file where pic will be stored

startActivityForResult(intent, TAKE_PICTURE_FROM_CAMERA);

基本上这会自动打开相机,当按下“拍照按钮”时,会调用 onActivityForResult() 方法,获取要管理的图像数据。

所以,我的疑问是,有没有办法在 React Native 中做到这一点?我的意思是,调用一个自动打开相机并返回数据的方法?

非常感谢。

【问题讨论】:

【参考方案1】:

最简单的方法是使用 ImagePicker 库https://github.com/react-community/react-native-image-picker

这允许您打开本机相机并使用照片中的数据获取提供的回调。

ImagePicker.launchCamera(options, (response)  => 
    // Response data
);

【讨论】:

【参考方案2】:

您还可以使用 expo-camera 和 expo-av(用于视频)。这是一个快速原型,它还管理设备权限。

import React,  useState, useRef, useEffect  from "react";
import 
  StyleSheet,
  Dimensions,
  View,
  Text,
  TouchableOpacity,
  SafeAreaView,
 from "react-native";
import  Camera  from "expo-camera";
import  Video  from "expo-av";
const WINDOW_HEIGHT = Dimensions.get("window").height;
const closeButtonSize = Math.floor(WINDOW_HEIGHT * 0.032);
const captureSize = Math.floor(WINDOW_HEIGHT * 0.09);
export default function App() 
  const [hasPermission, setHasPermission] = useState(null);
  const [cameraType, setCameraType] = useState(Camera.Constants.Type.back);
  const [isPreview, setIsPreview] = useState(false);
  const [isCameraReady, setIsCameraReady] = useState(false);
  const [isVideoRecording, setIsVideoRecording] = useState(false);
  const [videoSource, setVideoSource] = useState(null);
  const cameraRef = useRef();
  useEffect(() => 
    (async () => 
      const  status  = await Camera.requestPermissionsAsync();
      setHasPermission(status === "granted");
    )();
  , []);
  const onCameraReady = () => 
    setIsCameraReady(true);
  ;
  const takePicture = async () => 
    if (cameraRef.current) 
      const options =  quality: 0.5, base64: true, skipProcessing: true ;
      const data = await cameraRef.current.takePictureAsync(options);
      const source = data.uri;
      if (source) 
        await cameraRef.current.pausePreview();
        setIsPreview(true);
        console.log("picture source", source);
      
    
  ;
  const recordVideo = async () => 
    if (cameraRef.current) 
      try 
        const videoRecordPromise = cameraRef.current.recordAsync();
        if (videoRecordPromise) 
          setIsVideoRecording(true);
          const data = await videoRecordPromise;
          const source = data.uri;
          if (source) 
            setIsPreview(true);
            console.log("video source", source);
            setVideoSource(source);
          
        
       catch (error) 
        console.warn(error);
      
    
  ;
  const stopVideoRecording = () => 
    if (cameraRef.current) 
      setIsPreview(false);
      setIsVideoRecording(false);
      cameraRef.current.stopRecording();
    
  ;
  const switchCamera = () => 
    if (isPreview) 
      return;
    
    setCameraType((prevCameraType) =>
      prevCameraType === Camera.Constants.Type.back
        ? Camera.Constants.Type.front
        : Camera.Constants.Type.back
    );
  ;
  const cancelPreview = async () => 
    await cameraRef.current.resumePreview();
    setIsPreview(false);
    setVideoSource(null);
  ;
  const renderCancelPreviewButton = () => (
    <TouchableOpacity onPress=cancelPreview style=styles.closeButton>
      <View style=[styles.closeCross,  transform: [ rotate: "45deg" ] ] />
      <View
        style=[styles.closeCross,  transform: [ rotate: "-45deg" ] ]
      />
    </TouchableOpacity>
  );
  const renderVideoPlayer = () => (
    <Video
      source= uri: videoSource 
      shouldPlay=true
      style=styles.media
    />
  );
  const renderVideoRecordIndicator = () => (
    <View style=styles.recordIndicatorContainer>
      <View style=styles.recordDot />
      <Text style=styles.recordTitle>"Recording..."</Text>
    </View>
  );
  const renderCaptureControl = () => (
    <View style=styles.control>
      <TouchableOpacity disabled=!isCameraReady onPress=switchCamera>
        <Text style=styles.text>"Flip"</Text>
      </TouchableOpacity>
      <TouchableOpacity
        activeOpacity=0.7
        disabled=!isCameraReady
        onLongPress=recordVideo
        onPressOut=stopVideoRecording
        onPress=takePicture
        style=styles.capture
      />
    </View>
  );
  if (hasPermission === null) 
    return <View />;
  
  if (hasPermission === false) 
    return <Text style=styles.text>No access to camera</Text>;
  
  return (
    <SafeAreaView style=styles.container>
      <Camera
        ref=cameraRef
        style=styles.container
        type=cameraType
        flashMode=Camera.Constants.FlashMode.on
        onCameraReady=onCameraReady
        onMountError=(error) => 
          console.log("cammera error", error);
        
      />
      <View style=styles.container>
        isVideoRecording && renderVideoRecordIndicator()
        videoSource && renderVideoPlayer()
        isPreview && renderCancelPreviewButton()
        !videoSource && !isPreview && renderCaptureControl()
      </View>
    </SafeAreaView>
  );

const styles = StyleSheet.create(
  container: 
    ...StyleSheet.absoluteFillObject,
  ,
  closeButton: 
    position: "absolute",
    top: 35,
    left: 15,
    height: closeButtonSize,
    width: closeButtonSize,
    borderRadius: Math.floor(closeButtonSize / 2),
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#c4c5c4",
    opacity: 0.7,
    zIndex: 2,
  ,
  media: 
    ...StyleSheet.absoluteFillObject,
  ,
  closeCross: 
    width: "68%",
    height: 1,
    backgroundColor: "black",
  ,
  control: 
    position: "absolute",
    flexDirection: "row",
    bottom: 38,
    width: "100%",
    alignItems: "center",
    justifyContent: "center",
  ,
  capture: 
    backgroundColor: "#f5f6f5",
    borderRadius: 5,
    height: captureSize,
    width: captureSize,
    borderRadius: Math.floor(captureSize / 2),
    marginHorizontal: 31,
  ,
  recordIndicatorContainer: 
    flexDirection: "row",
    position: "absolute",
    top: 25,
    alignSelf: "center",
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "transparent",
    opacity: 0.7,
  ,
  recordTitle: 
    fontSize: 14,
    color: "#ffffff",
    textAlign: "center",
  ,
  recordDot: 
    borderRadius: 3,
    height: 6,
    width: 6,
    backgroundColor: "#ff0000",
    marginHorizontal: 5,
  ,
  text: 
    color: "#fff",
  ,
);

来源 - Instamobile

【讨论】:

以上是关于React Native 中如何使用手机摄像头拍照并获取数据的主要内容,如果未能解决你的问题,请参考以下文章

react-native构建基本页面5---调用拍照摄像头

React Native开发之expo中camera的基本使用

react和vue哪个比较好

React Native - 使用库 react-native-camera 调用摄像头扫描二维码以及条形码

如何使用带有 react-native-camera 的默认 iOS 相机控件

React Native Camera:拍照后,如何将其保存在应用程序本身而不是保存在图库中?