在移动应用中,相机功能 和 图片选择 是非常常见的需求,用户可以通过相机拍照或从相册中选择图片。React Native 提供了多种方式来实现相机和图片选择功能,包括使用第三方库(如 react-native-image-picker
)和调用原生模块。本章节将详细介绍如何使用 react-native-image-picker
库来实现相机和图片选择功能,包括基本用法、图片处理、权限管理以及自定义相机界面。
2.1 相机与图片选择概述
在移动应用中,相机和图片选择功能主要用于以下场景:
- 用户头像设置: 用户可以通过相机拍照或从相册中选择图片作为头像。
- 图片上传: 用户可以上传图片到服务器,如发布动态、分享照片等。
- 扫描二维码: 通过相机扫描二维码或条形码。
- 图片编辑: 用户可以对图片进行编辑,如裁剪、旋转、添加滤镜等。
React Native 提供了多种方式来实现相机和图片选择功能:
- 第三方库: 如
react-native-image-picker
,react-native-camera
,react-native-image-crop-picker
等,提供了封装好的 API,可以快速实现相机和图片选择功能。 - 原生模块: 可以通过原生代码实现自定义相机和图片选择功能,适用于需要高度定制化的场景。
本章节将重点介绍如何使用 react-native-image-picker
库来实现相机和图片选择功能。
2.2 使用 react-native-image-picker
库
react-native-image-picker
是一个流行的第三方库,用于实现相机和图片选择功能,支持 iOS 和 Android 平台。
2.2.1 安装 react-native-image-picker
npm install react-native-image-picker
链接原生依赖(React Native 0.60 及以上版本自动链接):
cd ios
pod install
cd ..
2.2.2 配置权限
iOS:
在 Info.plist
文件中添加相机和相册权限说明。
<key>NSCameraUsageDescription</key>
<string>需要访问相机以拍摄照片</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册以选择照片</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>需要保存照片到相册</string>
Android:
在 AndroidManifest.xml
文件中添加相机和存储权限。
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
注意: 对于 Android 6.0 及以上版本,还需要在代码中动态请求权限。
2.2.3 基本用法
请求相机或图片选择:
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';
const handleChooseImage = () => {
const options = {
mediaType: 'photo',
cameraType: 'back',
maxWidth: 1080,
maxHeight: 1080,
quality: 0.8,
};
launchImageLibrary(options, (response) => {
if (response.didCancel) {
console.log('用户取消选择图片');
} else if (response.errorCode) {
console.error('图片选择错误:', response.errorMessage);
} else {
const asset = response.assets[0];
console.log('选择的图片:', asset);
// 处理选择的图片
}
});
};
const handleTakePhoto = () => {
const options = {
mediaType: 'photo',
cameraType: 'back',
saveToPhotos: true,
maxWidth: 1080,
maxHeight: 1080,
quality: 0.8,
};
launchCamera(options, (response) => {
if (response.didCancel) {
console.log('用户取消拍照');
} else if (response.errorCode) {
console.error('拍照错误:', response.errorMessage);
} else {
const asset = response.assets[0];
console.log('拍摄的图片:', asset);
// 处理拍摄的图片
}
});
};
示例:
import React from 'react';
import { View, Button, Image, StyleSheet, Alert } from 'react-native';
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';
const CameraExample = () => {
const handleTakePhoto = () => {
const options = {
mediaType: 'photo',
cameraType: 'back',
saveToPhotos: true,
maxWidth: 1080,
maxHeight: 1080,
quality: 0.8,
};
launchCamera(options, (response) => {
if (response.didCancel) {
console.log('用户取消拍照');
} else if (response.errorCode) {
Alert.alert('拍照错误', response.errorMessage);
} else {
const asset = response.assets[0];
console.log('拍摄的图片:', asset);
// 处理拍摄的图片
}
});
};
const handleChooseImage = () => {
const options = {
mediaType: 'photo',
maxWidth: 1080,
maxHeight: 1080,
quality: 0.8,
};
launchImageLibrary(options, (response) => {
if (response.didCancel) {
console.log('用户取消选择图片');
} else if (response.errorCode) {
Alert.alert('图片选择错误', response.errorMessage);
} else {
const asset = response.assets[0];
console.log('选择的图片:', asset);
// 处理选择的图片
}
});
};
return (
<View style={styles.container}>
<Button title="拍照" onPress={handleTakePhoto} />
<Button title="选择图片" onPress={handleChooseImage} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
});
export default CameraExample;
解释:
launchCamera
方法: 打开相机进行拍照。launchImageLibrary
方法: 打开相册选择图片。options
参数: 配置相机或图片选择选项,如媒体类型、图片尺寸、质量等。- 回调函数: 处理用户取消、错误或选择结果。
2.2.4 处理选择的图片
react-native-image-picker
返回的图片信息包含图片的 URI、宽度、高度、大小等信息。可以使用 react-native-fast-image
或其他图片加载库来显示图片,并根据需要进行后续处理,如上传到服务器或保存到本地。
2.2.4.1 显示选择的图片
以下是如何使用 react-native-fast-image
显示用户选择的图片:
import React from 'react';
import { View, Button, StyleSheet, Alert } from 'react-native';
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';
import FastImage from 'react-native-fast-image';
const CameraExample = () => {
const [image, setImage] = React.useState(null);
const handleTakePhoto = () => {
const options = {
mediaType: 'photo',
cameraType: 'back',
saveToPhotos: true,
maxWidth: 1080,
maxHeight: 1080,
quality: 0.8,
};
launchCamera(options, (response) => {
if (response.didCancel) {
console.log('用户取消拍照');
} else if (response.errorCode) {
Alert.alert('拍照错误', response.errorMessage);
} else {
const asset = response.assets[0];
console.log('拍摄的图片:', asset);
setImage(asset);
}
});
};
const handleChooseImage = () => {
const options = {
mediaType: 'photo',
maxWidth: 1080,
maxHeight: 1080,
quality: 0.8,
};
launchImageLibrary(options, (response) => {
if (response.didCancel) {
console.log('用户取消选择图片');
} else if (response.errorCode) {
Alert.alert('图片选择错误', response.errorMessage);
} else {
const asset = response.assets[0];
console.log('选择的图片:', asset);
setImage(asset);
}
});
};
return (
<View style={styles.container}>
<View style={styles.buttonContainer}>
<Button title="拍照" onPress={handleTakePhoto} />
<Button title="选择图片" onPress={handleChooseImage} />
</View>
{image && (
<View style={styles.imageContainer}>
<FastImage
source={{ uri: image.uri }}
style={styles.image}
resizeMode={FastImage.resizeMode.cover}
/>
</View>
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
buttonContainer: {
flexDirection: 'row',
justifyContent: 'space-around',
width: '100%',
marginBottom: 20,
},
imageContainer: {
width: 300,
height: 300,
borderRadius: 10,
overflow: 'hidden',
marginBottom: 20,
},
image: {
width: '100%',
height: '100%',
},
});
export default CameraExample;
解释:
setImage(asset)
: 将选择的图片信息存储在组件状态中。FastImage
: 使用react-native-fast-image
显示图片,asset.uri
是图片的 URI。resizeMode
: 设置图片的缩放模式,如cover
,contain
,stretch
等。
2.2.4.2 图片上传
用户选择或拍摄图片后,通常需要将图片上传到服务器。以下是如何实现图片上传的示例:
import React from 'react';
import { View, Button, StyleSheet, Alert } from 'react-native';
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';
import axios from 'axios';
const CameraExample = () => {
const [image, setImage] = React.useState(null);
const handleTakePhoto = () => {
const options = {
mediaType: 'photo',
cameraType: 'back',
saveToPhotos: true,
maxWidth: 1080,
maxHeight: 1080,
quality: 0.8,
};
launchCamera(options, (response) => {
if (response.didCancel) {
console.log('用户取消拍照');
} else if (response.errorCode) {
Alert.alert('拍照错误', response.errorMessage);
} else {
const asset = response.assets[0];
setImage(asset);
uploadImage(asset);
}
});
};
const handleChooseImage = () => {
const options = {
mediaType: 'photo',
maxWidth: 1080,
maxHeight: 1080,
quality: 0.8,
};
launchImageLibrary(options, (response) => {
if (response.didCancel) {
console.log('用户取消选择图片');
} else if (response.errorCode) {
Alert.alert('图片选择错误', response.errorMessage);
} else {
const asset = response.assets[0];
setImage(asset);
uploadImage(asset);
}
});
};
const uploadImage = async (asset) => {
const formData = new FormData();
formData.append('file', {
uri: asset.uri,
type: asset.type,
name: asset.fileName || 'image.jpg',
});
try {
const response = await axios.post('https://example.com/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
Alert.alert('上传成功', `图片上传成功,图片ID: ${response.data.id}`);
} catch (error) {
Alert.alert('上传失败', '图片上传失败,请稍后重试');
}
};
return (
<View style={styles.container}>
<View style={styles.buttonContainer}>
<Button title="拍照" onPress={handleTakePhoto} />
<Button title="选择图片" onPress={handleChooseImage} />
</View>
{image && (
<View style={styles.imageContainer}>
<FastImage
source={{ uri: image.uri }}
style={styles.image}
resizeMode={FastImage.resizeMode.cover}
/>
</View>
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
buttonContainer: {
flexDirection: 'row',
justifyContent: 'space-around',
width: '100%',
marginBottom: 20,
},
imageContainer: {
width: 300,
height: 300,
borderRadius: 10,
overflow: 'hidden',
marginBottom: 20,
},
image: {
width: '100%',
height: '100%',
},
});
export default CameraExample;
解释:
uploadImage
函数: 使用axios
发送 POST 请求,将图片上传到服务器。FormData
: 用于构建 multipart/form-data 请求体。asset.uri
: 图片的 URI,用于上传。asset.type
: 图片的 MIME 类型。asset.fileName
: 图片的文件名,如果未提供,则使用默认名称。
2.2.4.3 图片保存到相册
用户拍摄或选择的图片可以保存到相册中。
示例:
import { writeToFile, copyFile, saveToLibrary } from 'react-native-image-picker';
const saveImageToAlbum = async (asset) => {
try {
const result = await saveToLibrary(asset.uri);
Alert.alert('保存成功', '图片已保存到相册');
} catch (error) {
Alert.alert('保存失败', '图片保存到相册失败');
}
};
作者简介
前腾讯电子签的前端负责人,现 whentimes tech CTO,专注于前端技术的大咖一枚!一路走来,从小屏到大屏,从 Web 到移动,什么前端难题都见过。热衷于用技术打磨产品,带领团队把复杂的事情做到极简,体验做到极致。喜欢探索新技术,也爱分享一些实战经验,帮助大家少走弯路!
温馨提示:可搜老码小张公号联系导师