简体   繁体   English

已解决 Expo-Camera,takePictureAsync 未定义(未处理的 promise 拒绝:TypeError:ref.current.takePictureAsync 不是函数)

[英]SOLVED Expo-Camera, takePictureAsync undefined (Unhandled promise rejection: TypeError: ref.current.takePictureAsync is not a function)

I'm trying to create react app with expo using expo-camera for taking pictures.我正在尝试使用 expo-camera 创建带有 expo 的反应应用程序来拍照。 I have separately components MeasurementCameraScreen and MeasurementCamera .我有单独的组件MeasurementCameraScreenMeasurementCamera I'm using useRef() hook to be able to call takePictureAsync() from the MeasuremenCameraScreen .我正在使用useRef()挂钩能够从MeasuremenCameraScreen调用takePictureAsync()

When pressing the take image -button takePicture() console.logs the ref , so I assume the onPress gets there, but then I get the following error message:当按下 take image -button takePicture() console.logs ref时,我假设 onPress 到达那里,但随后我收到以下错误消息:

[Unhandled promise rejection: TypeError: ref.current.takePictureAsync is not a function. (In 'ref.current.takePictureAsync(options)', 'ref.current.takePictureAsync' is undefined)]

I saw that people have also had same issues with takePictureAcync(), but I haven't found solution to my problem.我看到人们对 takePictureAcync() 也有同样的问题,但我还没有找到解决问题的方法。 I also tired to combine the MeasurementCameraScreen and MeasurementCamera components to one component, and with that I got the camera working, but I'm curious of why it doesn't work now?我也厌倦了将MeasurementCameraScreenMeasurementCamera组件组合到一个组件中,这样我就可以让相机工作了,但我很好奇为什么它现在不起作用? refs are new thing for me so I think there is something wrong with them. refs对我来说是新事物,所以我认为它们有问题。

Here are the components:以下是组件:

MeasurementCameraScreen

import { useRef } from 'react'
import { StyleSheet, TouchableOpacity, View } from 'react-native'

import MeasurementCamera from '../components/MeasurementCamera'
import Text from '../components/Text'

const MeasurementCameraScreen = () => {
    const cameraRef = useRef(null)

    return (
        <View style={styles.container}>
            <View style={styles.cameraContainer}>
                <MeasurementCamera ref={cameraRef}/>
            </View>
            <View>
            </View>
            <TouchableOpacity
                onPress={() => cameraRef.current.takePicture()}
                style={styles.buttonContainer}
            >
                <Text>
                    Take image
                </Text>
            </TouchableOpacity>
        </View>
    )

}

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    cameraContainer: {
        flex: 1,
    },
    buttonContainer: {
        width: '100%',
        height: 70,
        backgroundColor: 'white',
        justifyContent: 'center',
        alignItems: 'center',
        alignSelf: 'flex-end'
    },
})

export default MeasurementCameraScreen

MeasurementCamera

import { useState, useEffect, useImperativeHandle, forwardRef } from 'react'
import { StyleSheet } from "react-native"
import { Camera } from 'expo-camera'

import Text from './Text'

const MeasurementCamera = forwardRef((props, ref) => {
    const [hasPermission, setHasPermission] = useState(null)

    useEffect(() => {
        const getPermission = async () => {
            const { status } = await Camera.requestCameraPermissionsAsync()
            setHasPermission(status === 'granted')
        }
        getPermission()

    }, [])

    const takePicture = async () => {
        if (ref) {
            console.log(ref.current)
            const options = {
                quality: 1,
                base64: true
            }
            const picture = await ref.current.takePictureAsync(options)
            console.log(picture.uri)
        }
    }

    useImperativeHandle(ref, () => ({
        takePicture
    }))

    if (hasPermission === null) {
        return <Text>Requesting for camera permission</Text>
    } if (hasPermission === false) {
        return <Text>No access to camera</Text>
    }

    return (
       <Camera
            ref={ref}
            style={StyleSheet.absoluteFillObject}
        />
    )
})

MeasurementCamera.displayName = 'MeasurementCamera'

export default MeasurementCamera

EDIT: Solved the problem, check out the comment for solution: :)编辑:解决了问题,查看解决方案的评论::)

Okay I found the solution!好的,我找到了解决方案!

After reading the medium article @LouaySleman recommended about the expo-camera I understood that to be able to use the Expo Camera components functions I need to use ref .在阅读了@LouaySleman 推荐的关于 expo-camera 的媒体文章后,我了解到要能够使用Expo Camera组件功能,我需要使用ref So what I needed was two refs , one for the components to communicate and another one to be able to use the Camera takePictureAsync() function.所以我需要两个 refs一个用于组件通信,另一个用于能够使用Camera takePictureAsync() function。

Now that we have permissions to access the Camera, you should get familiar with the ref props on line 132, in the Camera component.现在我们有权限访问相机,你应该熟悉第 132 行的 ref 属性,在相机组件中。 There we have passed the cameraRef that was previously defined with useRef.在那里,我们传递了之前用 useRef 定义的 cameraRef。 In doing so, we will have access to interesting methods that we can call to control the Camera.在这样做的过程中,我们将可以访问可以调用来控制相机的有趣方法。

What you needed is to add two refs, one for the components to communicate and another one to be able to use the Camera takePictureAsync() function Please check this example from medium :您需要添加两个 refs,一个用于组件communicate ,另一个用于能够使用 Camera takePictureAsync() function 请从medium 中查看此示例:

import React, { useState, useRef, useEffect } from "react";
import {
 View,
 Text,
 TouchableOpacity,
 SafeAreaView,
 StyleSheet,
 Dimensions,
} from "react-native";
import { Camera } from "expo-camera";
import { Video } from "expo-av";
export default function CameraScreen() {
 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);
      }
    }
  };
 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("camera error", error);
        }}
 />
 <View style={styles.container}>
 {isVideoRecording && renderVideoRecordIndicator()}
 {videoSource && renderVideoPlayer()}
 {isPreview && renderCancelPreviewButton()}
 {!videoSource && !isPreview && renderCaptureControl()}
 </View>
 </SafeAreaView>
  );
}
const WINDOW_HEIGHT = Dimensions.get("window").height;
const closeButtonSize = Math.floor(WINDOW_HEIGHT * 0.032);
const captureSize = Math.floor(WINDOW_HEIGHT * 0.09);
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",
  },
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 [未处理的承诺拒绝:类型错误:未定义不是对象(评估&#39;_ref.about&#39;)] - [Unhandled promise rejection: TypeError: undefined is not an object (evaluating '_ref.about')] Expo 图像选择器:未处理 promise 拒绝:TypeError:未定义不是 object - Expo Image Picker: Unhandled promise rejection: TypeError: undefined is not an object [未处理的承诺拒绝:TypeError:未定义不是一个函数(正在评估&#39;_expo2.default.loadAsync&#39;)] - [Unhandled promise rejection: TypeError: undefined is not a function (evaluating '_expo2.default.loadAsync')] camera.takePictureAsync(options) 不是反应原生相机中的 function - camera.takePictureAsync(options) is not a function in react native camera Expo:未处理的 promise 拒绝:TypeError:未定义不是 object(评估“props.navigation”)] - Expo: Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'props.navigation')] 未处理的 promise 拒绝:TypeError: undefined is not an object(评估 '_context.t0.data.error')在 expo - Unhandled promise rejection: TypeError: undefined is not an object (evaluating '_context.t0.data.error') in expo 可能未处理的承诺拒绝未定义不是函数 - Possible Unhandled Promise Rejection undefined is not a function React Native 问题:[未处理的 promise 拒绝:TypeError:f 不是 function。 (在 'f()' 中,'f' 未定义)] - React Native issue : [Unhandled promise rejection: TypeError: f is not a function. (In 'f()', 'f' is undefined)] 未处理的承诺拒绝:TypeError:未定义不是一个函数,当在react native中为setState映射时会发生&#39;departureloc.map&#39;评估 - Unhandled promise rejection: TypeError: undefined is not a function evaluating 'departureloc.map' occurs when mapping for setState in react native 反应原生:未处理的承诺拒绝:类型错误:未定义不是对象 - React native: Unhandled promise rejection: TypeError: undefined is not an object
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM