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); 

结果如下:

posted @ 2020-01-15 15:43  XYQ全哥  阅读(5142)  评论(0编辑  收藏  举报