一、简介
同前面使用第三方库相机框架react-native-camera一样,对于原生的图片选择器的使用也有第三方框架提供。分别是react-native-image-picker和react-native-image-crop-picker。 react-native-image-picker库可以实现启动本地相册和照相机来采集图片,但是没有实现裁剪功能。针对头像上传的需求,一般都需要对图片进行裁剪,此时可以使用react-native-image-crop-picker库,该库同样实现了本地相册和照相机来采集图片,并且提供多选、图片裁剪等功能,支持iOS和Android两个平台。
react-native-image-picker:https://github.com/react-native-community/react-native-image-picker,基本样式如下:
react-native-image-crop-picker:https://github.com/ivpusic/react-native-image-crop-picker,基本样式如下:
二、配置plist文件
iOS10以后,访问用户的隐私文件需要授权,例如相册或者相机(录屏),因此需要打开Xcode并在项目的plist中添加授权字段。分别是NSCameraUsageDescription和NSPhotoLibraryUsageDescription以及NSMicrophoneUsageDescription(录制视屏需要访问麦克风)。
三、react-native-image-picker
1、安装:
- 注意自己的React-Native版本号,选择对应的库进行安装。我使用的0.44.3版本RN,之前安装高版本的react-native-image-picker总是编译失败。就装了低版本的。
- 命令行如下
//安装(本人安装的是低版本的:0.28.0)
npm install react-native-image-picker@0.28.0 --save
//链接(系统会自动在xcode中导入xcodeproj工程和.a静态包, link后面可以跟具体的库名,也可以不用跟)
react-native link react-native-image-picker@0.28.0
2、配置
- 安装react-native-image-picker库后需要打开xcode添加它的.xcodeproj工程和libRNImagePicker.a静态包到项目中。
- 注意事项:如果开发者手动执行了安装步骤的第2条命令行 “react-native link xxxxxx”,则这下面的两步就不用手动操作了,系统会帮助自动完成。
3、API
高版本和低版本的库其实差别也不是特别大,本人装的是低版本的,对低版本的api做一些简单的注释如下:
declare module "react-native-image-picker" {
//这个是操作ImagePicker的方法的回调信息(主要是操作界面被点击的信息和图片视屏的信息)
interface Response {
customButton: string;
didCancel: boolean;
error: string;
data: string;
uri: string;
origURL?: string;
isVertical: boolean;
width: number;
height: number;
fileSize: number;
type?: string;
fileName?: string;
path?: string;
latitude?: number;
longitude?: number;
timestamp?: string;
}
//在默认操作界面上添加自定义文案的按钮
interface CustomButtonOptions {
name?: string;
title?: string;
}
//在操作ImagePicker的方法之前,传入的一下配置选项。主要是界面的配置选项和相机以及图片视频的配置选项
interface Options {
title?: string;
cancelButtonTitle?: string;
takePhotoButtonTitle?: string;
chooseFromLibraryButtonTitle?: string;
customButtons?: Array<CustomButtonOptions>;
cameraType?: 'front' | 'back';
mediaType?: 'photo' | 'video' | 'mixed';
maxWidth?: number;
maxHeight?: number;
quality?: number;
videoQuality?: 'low' | 'medium' | 'high';
durationLimit?: number;
rotation?: number;
allowsEditing?: boolean;
noData?: boolean;
storageOptions?: StorageOptions;
}
//关于存储相关的配置选项
interface StorageOptions {
skipBackup?: boolean;
path?: string;
cameraRoll?: boolean;
waitUntilSaved?: boolean;
}
//ImagePicker的三方常用方法
class ImagePicker {
//选择图片(包括相机和图库选项)
static showImagePicker(options: Options, callback: (response: Response) => void): void;
//打开相机(可以拍照,也可以录制视频)
static launchCamera(options: Options, callback: (response: Response) => void): void;
//打开图库
static launchImageLibrary(options: Options, callback: (response: Response) => void): void;
}
export = ImagePicker;
}
4、使用
代码如下:
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
TouchableHighlight,
View
} from 'react-native';
const ImagePicker = require('react-native-image-picker');
export default class App extends Component {
//选择图片
_showImagePicker(){
//配置选项
const options = {
title: '选择图片',
cancelButtonTitle: '取消',
takePhotoButtonTitle: '拍照',
chooseFromLibraryButtonTitle: '图库',
customButtons: [
{name: 'share photo', title: '分享'},
],
cameraType: 'back',
mediaType: 'photo',
videoQuality: 'high',
durationLimit: 10,
maxWidth: 300,
maxHeight: 300,
quality: 0.8,
angle: 0,
allowsEditing: false,
noData: false,
storageOptions: {
skipBackup: true
}
};
//回调数据
ImagePicker.showImagePicker(options, (response => {
console.log("response: "+response);
}))
}
//打开相机
_launchCamera(){
//配置选项
const options = {
cameraType: 'front', //前置摄像头
mediaType: 'photo' //进行拍照
};
//回调数据
ImagePicker.launchCamera(options, (response => {
console.log("response: "+response);
}))
}
//打开图库
_launchImageLibrary(){
//配置选项
const options = { mediaType: 'photo' };
//回调数据
ImagePicker.launchImageLibrary(options, (response => {
console.log("response: "+response);
}))
}
render() {
return (
<View style={styles.container}>
<TouchableHighlight onPress={this._showImagePicker.bind(this)}>
<Text style={{color:'red',fontSize:30}}>选择图片</Text>
</TouchableHighlight>
<TouchableHighlight onPress={this._launchCamera.bind(this)}>
<Text style={{color:'red',marginTop:30,fontSize:30}}>打开相机</Text>
</TouchableHighlight>
<TouchableHighlight onPress={this._launchImageLibrary.bind(this)}>
<Text style={{color:'red',marginTop:30,fontSize:30}}>打开图库</Text>
</TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
}
});
AppRegistry.registerComponent('App', () => App);
踩坑经验:0.28.0这个版本的库有点问题,打开相机和图库时,app会很慢,甚至严重到闪退。这是由于作者对于打开相机launchCamear和打开图库launchImageLibrary的方法,没有放在主线程中执行,修改库文件即可,如下:
运行结果如下所示:
四、react-native-image-crop-picker
1、安装
- 安装react-native-image-crop-picker也需要根据自己的ReactNative版本。在github上已经写明安装的要求,如下:
如果您使用的是react-native> = 0.60,请使用react-native-image-crop-picker版本> = 0.25.0。 否则,使用版本<0.25.0。
- 命令行(同上)
//安装
npm install react-native-image-crop-picker@0.24.1 --save
//链接
react-native link react-native-image-crop-picker@0.24.1
2、配置
- 配置步骤和上面的react-native-image-picker一样,不再赘述。但是注意,仍需要手动添加如下两个框架,否则会报错如下:
dyld: Library not loaded: @rpath/QBImagePicker.framework/QBImagePicker
Referenced from: /private/var/containers/Bundle/Application/1816C8C9-80A2-4860-919B-CD415E245C4C/RNDemo.app/RNDemo
Reason: image not found
3、API
它的类构成也很简单,如下所示:
declare module "react-native-image-crop-picker" {
//配置裁剪选项,在调用方法时需要传入的参数
export interface Options {
cropping?: boolean;
width?: number;
height?: number;
multiple?: boolean;
path?: string;
includeBase64?: boolean;
includeExif?: boolean;
avoidEmptySpaceAroundImage?: boolean;
cropperActiveWidgetColor?: string;
cropperStatusBarColor?: string;
cropperToolbarColor?: string;
cropperToolbarTitle?: string;
freeStyleCropEnabled?: boolean;
cropperTintColor?: string;
cropperCircleOverlay?: boolean;
disableCropperColorSetters?: boolean;
maxFiles?: number;
waitAnimationEnd?: boolean;
smartAlbums?: string[];
useFrontCamera?: boolean;
compressVideoPreset?: string;
compressImageMaxWidth?: number;
compressImageMaxHeight?: number;
compressImageQuality?: number;
loadingLabelText?: string;
mediaType?: string;
showsSelectedCount?: boolean;
forceJpg?: boolean;
showCropGuidelines?: boolean;
hideBottomControls?: boolean;
enableRotationGesture?: boolean;
cropperCancelText?: string;
cropperChooseText?: string;
}
//关于图片的信息
export interface Image {
path: string;
size: number;
data: null | string;
width: number;
height: number;
mime: string;
exif: null | object;
cropRect: null | CropRect;
filename: string;
creationDate: string;
modificationDate?: string;
}
//裁剪的局域信息
export interface CropRect {
x: number;
y: number;
width: number;
height: number;
}
//打开选择器,返回值是一个Promise异步函数,结果是图片或图片数组
export function openPicker(options: Options): Promise<Image | Image[]>;
//打开相机,返回值是一个Promise异步函数,结果是图片或图片数组
export function openCamera(options: Options): Promise<Image | Image[]>;
//打开裁剪器,需要指定要裁剪资源的路径path ,返回值是一个Promise异步函数,结果是图片
export function openCropper(options: Options): Promise<Image>;
//清除所有临时缓存,返回值是一个Promise异步函数,无结果
export function clean(): Promise<void>;
//清除某一个资源的临时缓存,返回值是一个Promise异步函数,无结果
export function cleanSingle(path: string): Promise<void>;
//裁剪选择器
export interface ImageCropPicker {
openPicker(options: Options): Promise<Image | Image[]>;
openCamera(options: Options): Promise<Image | Image[]>;
openCropper(options: Options): Promise<Image>;
clean(): Promise<void>;
cleanSingle(path: string): Promise<void>;
}
const ImageCropPicker: ImageCropPicker;
export default ImageCropPicker;
}
4、使用
针对api,简单使用如下:
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
TouchableHighlight,
View
} from 'react-native';
import ImageCropPicker from 'react-native-image-crop-picker';
export default class App extends Component {
//打开选择器: 裁剪单张图片
_openPicker1(){
const option = { width: 300, height: 400, mediaType:"photo", cropping: true };
ImageCropPicker.openPicker(option).then(image =>{
alert(image);
}, (error) =>{
alert(error);
});
}
//打开选择器: 选择多张图片
_openPicker2(){
const option = {mediaType:"photo", multiple:true};
ImageCropPicker.openPicker(option).then(images =>{
alert(images);
}, (error) =>{
alert(error);
});
}
//打开选择器: 选择视屏资源
_openPicker3(){
const option = { mediaType:"video" };
ImageCropPicker.openPicker(option).then(video =>{
alert(video);
}, (error) =>{
alert(error);
});
}
//打开相机: 拍照
_openCamera1(){
const option = { width: 300, height: 400, mediaType:"photo", cropping: true };
ImageCropPicker.openCamera(option).then(image =>{
alert(image);
}, (error) =>{
alert(error);
});
}
//打开相机: 视频
_openCamera2(){
const option = { mediaType:"video" };
ImageCropPicker.openCamera(option).then(video =>{
alert(video);
},(error) =>{
alert(error);
});
}
//打开截取器: 直接裁剪指定路径下的图片
_openCropper(){
const option = { path:"car.png", width: 100, height: 100, mediaType:"photo", cropping: true };
ImageCropPicker.openCropper(option).then(image => {
alert(image);
},(error) =>{
alert(error);
});
}
render() {
return (
<View style={styles.container}>
<TouchableHighlight onPress={this._openPicker1.bind(this)}>
<Text style={{color:'red',marginBottom:30,fontSize:25}}>打开选择器:裁剪单张图片</Text>
</TouchableHighlight>
<TouchableHighlight onPress={this._openPicker2.bind(this)}>
<Text style={{color:'red',marginBottom:30,fontSize:25}}>打开选择器:选择多张图片</Text>
</TouchableHighlight>
<TouchableHighlight onPress={this._openPicker3.bind(this)}>
<Text style={{color:'red',marginTop:0,fontSize:25}}>打开选择器:选择视屏资源</Text>
</TouchableHighlight>
<TouchableHighlight onPress={this._openCamera1.bind(this)}>
<Text style={{color:'red',marginTop:30,fontSize:25}}>打开相机: 拍照</Text>
</TouchableHighlight>
<TouchableHighlight onPress={this._openCamera2.bind(this)}>
<Text style={{color:'red',marginTop:30,fontSize:25}}>打开相机: 视频</Text>
</TouchableHighlight>
<TouchableHighlight onPress={this._openCropper.bind(this)}>
<Text style={{color:'red',marginTop:30,fontSize:25}}>打开裁剪器</Text>
</TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
}
});
AppRegistry.registerComponent('App', () => App);