ReactNative: 使用第三方库图像选择器react-native-image-picker和react-native-image-crop-picker
一、简介
同前面使用第三方库相机框架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);
结果如下: