如何使用 expo react native camera 拍摄照片?
How to snap pictures using expo react native camera?
我刚开始在 Expo 中使用 React Native,所以我有点困惑。所以,我制作了一个我在主屏幕中导入的相机组件。一切看起来都很好。但是我不能拍照。我无法单击快照图标并保存图像。有没有我错过的组件?
我只在下面发布了 CameraComponent
class。
Camera.js
class CameraComponent extends Component {
state = {
hasCameraPermission: null,
type: Camera.Constants.Type.back
}
async componentWillMount() {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === 'granted' })
}
render() {
const { hasCameraPermission } = this.state
if (hasCameraPermission === null) {
return <View />
}
else if (hasCameraPermission === false) {
return <Text> No access to camera</Text>
}
else {
return (
<View style={{ flex: 1 }}>
<Camera
style={{ flex: 1, justifyContent: 'space-between' }}
type={this.state.type}
>
<Header
searchBar
rounded
style={{
position: 'absolute',
backgroundColor: 'transparent',
left: 0,
top: 0,
right: 0,
zIndex: 100,
alignItems: 'center'
}}
>
<View style={{ flexDirection: 'row', flex: 4 }}>
<Ionicons name="md-camera" style={{ color: 'white' }} />
<Item style={{ backgroundColor: 'transparent' }}>
<Icon name="ios-search" style={{ color: 'white', fontSize: 24, fontWeight: 'bold' }}></Icon>
</Item>
</View>
<View style={{ flexDirection: 'row', flex: 2, justifyContent: 'space-around' }}>
<Icon name="ios-flash" style={{ color: 'white', fontWeight: 'bold' }} />
<Icon
onPress={() => {
this.setState({
type: this.state.type === Camera.Constants.Type.back ?
Camera.Constants.Type.front :
Camera.Constants.Type.back
})
}}
name="ios-reverse-camera"
style={{ color: 'white', fontWeight: 'bold' }}
/>
</View>
</Header>
<View style={{ flexDirection: 'row', justifyContent: 'space-between', paddingHorizontal: 30, marginBottom: 15, alignItems: 'flex-end' }}>
<Ionicons name="ios-map" style={{ color: 'white', fontSize: 36 }}></Ionicons>
<View></View>
<View style={{ alignItems: 'center' }}>
<MaterialCommunityIcons name="circle-outline" // This is the icon which should take and save image
style={{ color: 'white', fontSize: 100 }}
></MaterialCommunityIcons>
<Icon name="ios-images" style={{ color: 'white', fontSize: 36 }} />
</View>
</View>
</Camera>
</View>
)
}
}
}
export default CameraComponent;
中间的图标即圆圈图标应该会自动拍摄并保存图像。
您是要在真实的物理设备上执行此操作吗?不能用模拟器拍照。
所以你需要告诉你的 'circle icon' 拍照。首先,我会像这样添加对您的相机的引用
<Camera style={{ flex: 1 }}
ref={ (ref) => {this.camera = ref} }
type={this.state.type}>
然后创建一个实际告诉您的应用拍照的函数:
async snapPhoto() {
console.log('Button Pressed');
if (this.camera) {
console.log('Taking photo');
const options = { quality: 1, base64: true, fixOrientation: true,
exif: true};
await this.camera.takePictureAsync(options).then(photo => {
photo.exif.Orientation = 1;
console.log(photo);
});
}
}
现在让你的图标有一个 onPress() 来拍照。我做了这样的事情。
<TouchableOpacity style={styles.captureButton} onPress={this.snapPhoto.bind(this)}>
<Image style={{width: 100, height: 100}} source={require('../assets/capture.png')}
/>
</TouchableOpacity>
您可能还想创建一个呈现图像预览或类似内容的视图。 Expo 文档有一个很好的入门示例。请注意,Expo 创建了一个名为 'Camera' 的缓存文件夹,这是图像最初所在的位置。
您需要向相机添加一个引用 class 才能在您自己的 'handle' 方法中调用它的 takePictureAsync 函数。
cameraRef = React.createRef();
<Camera ref={this.cameraRef}>...</Camera>
调用引用相机的方法时不要忘记“.current”。
handlePhoto = async () => {
if(this.cameraRef){
let photo = await this.cameraRef.current.takePictureAsync();
console.log(photo);
}
}
然后只需在用作拍照按钮的可触摸元素上调用您的 'handle' 方法。
<TouchableOpacity
style={{width:60, height:60, borderRadius:30, backgroundColor:"#fff"}}
onPress={this.handlePhoto} />
您应该能够在控制台中看到记录的照片。
可以在异步takePictureAsync函数returns时使用"onPictureSaved"这样就可以抓取照片对象了:
takePicture = () => {
if (this.camera) {
this.camera.takePictureAsync({ onPictureSaved: this.onPictureSaved });
}
};
onPictureSaved = photo => {
console.log(photo);
}
在视图中,您将拥有一个具有 ref 的相机组件:
<Camera style={styles.camera} type={this.state.type} ref={(ref) => { this.camera = ref }} >
还有一个按下时将调用拍照功能的按钮:
<TouchableOpacity style={styles.captureButton} onPress={this.takePicture} />
您也可以在功能组件中使用通过 React Hook 创建的引用来执行此操作。这是一个基于 expo SDK 38 Camera 组件的示例 https://docs.expo.io/versions/v38.0.0/sdk/camera/
import React, { useState, useEffect, useRef } from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
import { Camera } from 'expo-camera';
export default function App() {
const [hasPermission, setHasPermission] = useState(null);
const [type, setType] = useState(Camera.Constants.Type.back);
const ref = useRef(null)
useEffect(() => {
(async () => {
const { status } = await Camera.requestPermissionsAsync();
setHasPermission(status === 'granted');
})();
}, []);
_takePhoto = async () => {
const photo = await ref.current.takePictureAsync()
console.debug(photo)
}
if (hasPermission === null) {
return <View />;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={{ flex: 1 }}>
<Camera style={{ flex: 1 }} type={type} ref={ref}>
<View
style={{
flex: 1,
backgroundColor: 'transparent',
flexDirection: 'row',
}}>
<TouchableOpacity
style={{
flex: 0.1,
alignSelf: 'flex-end',
alignItems: 'center',
}}
onPress={() => {
setType(
type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back
);
}}>
<Text style={{ fontSize: 18, marginBottom: 10, color: 'white' }}> Flip </Text>
</TouchableOpacity>
<TouchableOpacity
onPress={_takePhoto}
>
<Text>Snap Photo</Text>
</TouchableOpacity>
</View>
</Camera>
</View>
);
}
我没有检查 UI 看起来像什么,但要点是利用 React.useRef
并将引用附加到您的 <Camera/>
组件。然后您可以调用 ref.current.takePictureAsync
来捕获和访问新图像。请查看下方以了解拍摄照片的重要相关片段。
import React from 'react'
/* ... other imports
*/
export default CameraScene = () => {
/* ... other state and permission logic
*/
const ref = useRef(null)
const _takePhoto = async () => {
const photo = await ref.current.takePictureAsync()
console.debug(photo)
}
return (
<Camera style={{flex: 1}} ref={ref}> /* ...
... other ui logic
*/
</Camera>
)
}
在此处了解有关 useRef
的更多信息 https://reactjs.org/docs/hooks-reference.html#useref)
我刚开始在 Expo 中使用 React Native,所以我有点困惑。所以,我制作了一个我在主屏幕中导入的相机组件。一切看起来都很好。但是我不能拍照。我无法单击快照图标并保存图像。有没有我错过的组件?
我只在下面发布了 CameraComponent
class。
Camera.js
class CameraComponent extends Component {
state = {
hasCameraPermission: null,
type: Camera.Constants.Type.back
}
async componentWillMount() {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === 'granted' })
}
render() {
const { hasCameraPermission } = this.state
if (hasCameraPermission === null) {
return <View />
}
else if (hasCameraPermission === false) {
return <Text> No access to camera</Text>
}
else {
return (
<View style={{ flex: 1 }}>
<Camera
style={{ flex: 1, justifyContent: 'space-between' }}
type={this.state.type}
>
<Header
searchBar
rounded
style={{
position: 'absolute',
backgroundColor: 'transparent',
left: 0,
top: 0,
right: 0,
zIndex: 100,
alignItems: 'center'
}}
>
<View style={{ flexDirection: 'row', flex: 4 }}>
<Ionicons name="md-camera" style={{ color: 'white' }} />
<Item style={{ backgroundColor: 'transparent' }}>
<Icon name="ios-search" style={{ color: 'white', fontSize: 24, fontWeight: 'bold' }}></Icon>
</Item>
</View>
<View style={{ flexDirection: 'row', flex: 2, justifyContent: 'space-around' }}>
<Icon name="ios-flash" style={{ color: 'white', fontWeight: 'bold' }} />
<Icon
onPress={() => {
this.setState({
type: this.state.type === Camera.Constants.Type.back ?
Camera.Constants.Type.front :
Camera.Constants.Type.back
})
}}
name="ios-reverse-camera"
style={{ color: 'white', fontWeight: 'bold' }}
/>
</View>
</Header>
<View style={{ flexDirection: 'row', justifyContent: 'space-between', paddingHorizontal: 30, marginBottom: 15, alignItems: 'flex-end' }}>
<Ionicons name="ios-map" style={{ color: 'white', fontSize: 36 }}></Ionicons>
<View></View>
<View style={{ alignItems: 'center' }}>
<MaterialCommunityIcons name="circle-outline" // This is the icon which should take and save image
style={{ color: 'white', fontSize: 100 }}
></MaterialCommunityIcons>
<Icon name="ios-images" style={{ color: 'white', fontSize: 36 }} />
</View>
</View>
</Camera>
</View>
)
}
}
}
export default CameraComponent;
中间的图标即圆圈图标应该会自动拍摄并保存图像。
您是要在真实的物理设备上执行此操作吗?不能用模拟器拍照。
所以你需要告诉你的 'circle icon' 拍照。首先,我会像这样添加对您的相机的引用
<Camera style={{ flex: 1 }}
ref={ (ref) => {this.camera = ref} }
type={this.state.type}>
然后创建一个实际告诉您的应用拍照的函数:
async snapPhoto() {
console.log('Button Pressed');
if (this.camera) {
console.log('Taking photo');
const options = { quality: 1, base64: true, fixOrientation: true,
exif: true};
await this.camera.takePictureAsync(options).then(photo => {
photo.exif.Orientation = 1;
console.log(photo);
});
}
}
现在让你的图标有一个 onPress() 来拍照。我做了这样的事情。
<TouchableOpacity style={styles.captureButton} onPress={this.snapPhoto.bind(this)}>
<Image style={{width: 100, height: 100}} source={require('../assets/capture.png')}
/>
</TouchableOpacity>
您可能还想创建一个呈现图像预览或类似内容的视图。 Expo 文档有一个很好的入门示例。请注意,Expo 创建了一个名为 'Camera' 的缓存文件夹,这是图像最初所在的位置。
您需要向相机添加一个引用 class 才能在您自己的 'handle' 方法中调用它的 takePictureAsync 函数。
cameraRef = React.createRef();
<Camera ref={this.cameraRef}>...</Camera>
调用引用相机的方法时不要忘记“.current”。
handlePhoto = async () => {
if(this.cameraRef){
let photo = await this.cameraRef.current.takePictureAsync();
console.log(photo);
}
}
然后只需在用作拍照按钮的可触摸元素上调用您的 'handle' 方法。
<TouchableOpacity
style={{width:60, height:60, borderRadius:30, backgroundColor:"#fff"}}
onPress={this.handlePhoto} />
您应该能够在控制台中看到记录的照片。
可以在异步takePictureAsync函数returns时使用"onPictureSaved"这样就可以抓取照片对象了:
takePicture = () => {
if (this.camera) {
this.camera.takePictureAsync({ onPictureSaved: this.onPictureSaved });
}
};
onPictureSaved = photo => {
console.log(photo);
}
在视图中,您将拥有一个具有 ref 的相机组件:
<Camera style={styles.camera} type={this.state.type} ref={(ref) => { this.camera = ref }} >
还有一个按下时将调用拍照功能的按钮:
<TouchableOpacity style={styles.captureButton} onPress={this.takePicture} />
您也可以在功能组件中使用通过 React Hook 创建的引用来执行此操作。这是一个基于 expo SDK 38 Camera 组件的示例 https://docs.expo.io/versions/v38.0.0/sdk/camera/
import React, { useState, useEffect, useRef } from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
import { Camera } from 'expo-camera';
export default function App() {
const [hasPermission, setHasPermission] = useState(null);
const [type, setType] = useState(Camera.Constants.Type.back);
const ref = useRef(null)
useEffect(() => {
(async () => {
const { status } = await Camera.requestPermissionsAsync();
setHasPermission(status === 'granted');
})();
}, []);
_takePhoto = async () => {
const photo = await ref.current.takePictureAsync()
console.debug(photo)
}
if (hasPermission === null) {
return <View />;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={{ flex: 1 }}>
<Camera style={{ flex: 1 }} type={type} ref={ref}>
<View
style={{
flex: 1,
backgroundColor: 'transparent',
flexDirection: 'row',
}}>
<TouchableOpacity
style={{
flex: 0.1,
alignSelf: 'flex-end',
alignItems: 'center',
}}
onPress={() => {
setType(
type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back
);
}}>
<Text style={{ fontSize: 18, marginBottom: 10, color: 'white' }}> Flip </Text>
</TouchableOpacity>
<TouchableOpacity
onPress={_takePhoto}
>
<Text>Snap Photo</Text>
</TouchableOpacity>
</View>
</Camera>
</View>
);
}
我没有检查 UI 看起来像什么,但要点是利用 React.useRef
并将引用附加到您的 <Camera/>
组件。然后您可以调用 ref.current.takePictureAsync
来捕获和访问新图像。请查看下方以了解拍摄照片的重要相关片段。
import React from 'react'
/* ... other imports
*/
export default CameraScene = () => {
/* ... other state and permission logic
*/
const ref = useRef(null)
const _takePhoto = async () => {
const photo = await ref.current.takePictureAsync()
console.debug(photo)
}
return (
<Camera style={{flex: 1}} ref={ref}> /* ...
... other ui logic
*/
</Camera>
)
}
在此处了解有关 useRef
的更多信息 https://reactjs.org/docs/hooks-reference.html#useref)