一、簡介
同前面使用第三方庫相機框架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);
結果如下:

