react-native系列(20)API篇:照片或视频的获取、保存、选择与上传

照片获取与保存

官方提供了CameraRoll模块访问本地相册的功能,它包含两个方法:

方法描述
CameraRoll.getPhotos(params);

表示获取相册数据,参数格式如下:

{

      first:number类型,要获取的照片数

      assetType:All | Videos | Photos,默认为Photos

      after:用于记录上一次获取到哪一张图片

      ... // 其它不常用可看官方文档解释

CameraRoll.saveToCameraRoll(tag, [type]);

在 Android 上,tag是一个本地 URI,例如"file:///sdcard/img.png"。

在 iOS, tag可以是任意图片 URI。

如果后缀名为.mov或.mp4,则保存为视频,其它后缀均保存为图片。

如果你需要自定义保存类型,可以在第二个参数type中定义,类型只能是 'photo' 或者 'video'

现在虚拟机中有三张照片,每次获取并更新一张,完整demo如下:关于请求权限问题,可以浏览上一篇博客《react-native系列(19)API篇:请求系统权限(相册等)的方法》

import React from 'react';
import { View, Text, Button, Image, Platform, CameraRoll, PermissionsAndroid, Alert } from 'react-native';

class CameraRollAPI extends React.Component {

    state = {
        images: [], // 存放照片数据
        cursorEnd: '', // 上一次相册中获取照片的结束标记
        hasNextPage: true // 是否还有下一张照片
    }

    UNSAFE_componentWillMount() {
        this.requestReadPermission();
    }

    getPhotos(){
        if(this.state.hasNextPage){
            let queryNativePictuire = {
                first: 1, 
                assetType: 'Photos' // All全部|Videos录像|Photos照片(默认)
            };
            if (this.state.cursorEnd) {
                queryNativePictuire.after = this.state.cursorEnd;
            }
            CameraRoll.getPhotos(queryNativePictuire).then((result) => {
                let pageInfo = result.page_info;
                this.setState({ images: result.edges, cursorEnd: pageInfo.end_cursor, hasNextPage: pageInfo.has_next_page });
            }).catch((error) => {
                console.log(error);
            });
        }else{
            Alert.alert('提示','已经没有下一张照片');
        }
    }

    async requestReadPermission() {
        try {
            const os = Platform.OS; // android or ios
            if(os === 'android'){
                const granted = await PermissionsAndroid.request(
                    PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
                    {
                        //第一次请求【拒绝】后提示用户你为什么要这个权限
                        'title': '我要读写权限',
                        'message': '没权限我不能工作,同意就好了'
                    }
                );
                if (granted === PermissionsAndroid.RESULTS.GRANTED) {
                    // 已获取了读写权限
                    this.getPhotos();
                } else {
                    // 获取读写权限失败
                }
            }else{
                this.getPhotos();
            }
        } catch (err) {
            console.log(err.toString());
        }
    }

    _getNextPhoto = () => {
        this.getPhotos();
    }

    _saveImg = () => {
        const img = 'http://www.helloui.net/assets/watch.jpg'; // 网络图片在android中会报错
        var promise = CameraRoll.saveToCameraRoll(img); // 在 Android 上,img是一个本地 URI,例如"file:///sdcard/img.png"。在 iOS, img可以是任意图片 URI
        promise.then(function(result) {
            alert('保存成功!地址如下:\n' + result);
        }).catch(function(error) {
            alert('保存失败!\n' + error);
        });
    }

    _renderImg = () => {
        const side = 200 ;
        if(this.state.images.length > 0){
            const image = this.state.images[0].node.image;
            return(
                <View>
                    <Image 
                        source={{ uri: image.uri }} 
                        style={{width:side, height:side}} 
                    />
                </View>
            );
        }else{
            return null;
        }
    }

    render(){
        return(
            <View>
                <Text>照片:</Text>
                {this._renderImg()}
                <Button 
                    title='更换一张照片'
                    onPress={this._getNextPhoto}
                />
                <Button 
                    title='保存一张网络图片'
                    onPress={this._saveImg}
                />
            </View>
        );
    }
}

export default CameraRollAPI;

效果:

照片选择

在app需求中,常常从相册中选取一张照片或视频然后上传。这种情况最常用的是react-native-image-picker插件,它即可以适用于照片也可以适用于视频,通过该插件可以很方便的获取想要的照片或视频数据。

安装:

npm install react-native-image-picker@latest --save
react-native link

安装成功后,如果使用VSCode编辑器,可能会存在一个bug:打开android/settings.gradle文件,正常情况下会看到如下脚本:

include ':react-native-vector-icons'
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
include ':react-native-image-picker'
project(':react-native-image-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-image-picker/android')

这表示你的安装时正确的。如果后面的路径 ' / ' 变为反斜杠 ' \ ' 将无法使用,改正过来即可。

完整demo代码:

import React from 'react';
import { View, Button, Image } from 'react-native';
import ImagePicker from 'react-native-image-picker';

class ImagePickerAPI extends React.Component {

    state = {
        avatarSource: {
            uri: ''
        }
    }

    onPressImg = () => {
        const options = {
            title: '选择图片', 
            cancelButtonTitle: '取消',
            takePhotoButtonTitle: '拍照', 
            chooseFromLibraryButtonTitle: '相册', 
            customButtons: [
                {name: '唯一名称', title: '显示的自定义按钮内容'},
              ],
            cameraType: 'back', // 类型 'front' or 'back' ,前置还是后置摄像头
            mediaType: 'photo', // 图片或视频 'photo', 'video', or 'mixed' on iOS, 'photo' or 'video' on Android
            videoQuality: 'high',  // 视频质量 'low', 'medium', or 'high' on iOS, 'low' or 'high' on Android
            durationLimit: 10,  // 最大录制时间
            maxWidth: 300, // 返回的图片数据的最大宽 photos only 只有图片有这个属性
            maxHeight: 300, // 返回的图片数据的最大高 photos only
            quality: 0.8, // 图片质量 0 to 1 photos only
            angle: 90,
            allowsEditing: false, // 是否可以编辑
            noData: false, // 如果为true,则禁用data生成的base64 字段(极大地提高大图片的性能)
            storageOptions: {
                skipBackup: true   // 如果true,该照片将不会备份到iCloud
            }
        };

        ImagePicker.showImagePicker(options, (response) => {
            if (response.didCancel) {
                console.log('取消');
            }
            else if (response.error) {
                console.log('发生错误: ', response.error);
            }
            else if (response.customButton) {
                console.log('自定义按钮被点击,它的名称是:', response.customButton);
            }
            else {
                console.log('Response = ', response); // 选择或拍摄的照片数据对象
                let source = { uri: response.uri };
                // You can also display the image using data:
                // let source = { uri: 'data:image/jpeg;base64,' + response.data };
                this.setState({
                    avatarSource: source
                });
            }
        });
    }

    onPressVideo = () => {
        const options = {
            title: '选择视频',
            cancelButtonTitle: '取消',
            takePhotoButtonTitle: '录制视频',
            chooseFromLibraryButtonTitle: '选择视频',
            mediaType: 'video',
            videoQuality: 'medium' // 视频质量 'low', 'medium', or 'high' on iOS, 'low' or 'high' on Android
        };

        ImagePicker.showImagePicker(options, (response) => {
            if (response.didCancel) {
                console.log('取消');
            }
            else if (response.error) {
                console.log('发生错误: ', response.error);
            }
            else if (response.customButton) {
                console.log('自定义按钮被点击,它的名称是:', response.customButton);
            }
            else {
                console.log('Response = ', response); // 选择或录取的视频数据对象
                this.setState({
                    videoSource: response.uri
                });
            }
        });
    }

    _renderImg = () => {
        const side = 200 ;
        if(this.state.avatarSource.uri){
            return(
                <View>
                    <Image 
                        source={{ uri: this.state.avatarSource.uri }} 
                        style={{width:side, height:side}} 
                    />
                </View>
            );
        }else{
            return null;
        }
    }

    render(){
        return(
            <View>
                <Button 
                    title='照片'
                    onPress={this.onPressImg}
                />

                <Button 
                    title='视频'
                    onPress={this.onPressVideo}
                />

                {this._renderImg()}
            </View>
        );
    }
}

export default ImagePickerAPI;

效果:

照片上传

使用FormData数据格式封装后上传,核心代码如下:

const file = {
    uri: imageURI, // 本地图片路径
    name: `${uuid()}.jpg`, // 图片名称
    type: 'image/jpg' // 图片格式
};

const body = new FormData();
body.append('file',file);   

fetch(FILE_UPLOAD_URL, {
    method: 'POST',
    body,
    headers: {
        'Accept': 'application/json',  // 返回json数据格式
        'Content-Type':'multipart/form-data'
    }
})
.then(checkStatus)
.then(response => response.json())
.then(response => {
    console.log(response);
})
.catch(error => {
    console.log(error);
});

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值