实现上面的效果需要的库如下
react-native-image-picker
react-native-progress
先来说下是如何实现点击上传图标弹出optionModal上传选项的动画的.
整个optionModal区域是一个Animated.View, render 的时候他的position 是 absolute的, 整个位置是隐藏在屏幕下的, bottom: - 200. 点击按钮之后,用Animated.spring 把 bottom 的值 调整到 0 , 这样隐藏的部分就弹出来了
const styles = StyleSheet.create({
container: {
backgroundColor: theme.screen_background_color,
zIndex: 100,
height: 200,
width: '100%',
position: 'absolute',
bottom: - 200),
backgroundColor: 'rgb(255,255,255)',
alignItems: 'center',
borderTopWidth: 1,
borderTopColor: theme.divider_color,
}
showOptionModal() {
Animated.spring(
this.modalPos, { toValue: 0, }
).start();
<Animated.View style={[styles.container, { bottom: this.modalPos }]}>
</Animated.View>
还有就是区域里面的upload video 和 upload photos 图标动画有个先后顺序,这里的处理就是upload video 这个图标用了个settimeout, 让他的动画触发晚了个 0.1秒而已。实现的方法也是跟optionModal弹出的方法一样。
接下来就是选择手机里面的图片或者视频了,这里我们会用一个库叫做 react-native-image-picker, 这个库应该是大家很经常会使用到的, 就是选择手机里面的视频和图片,或者可以用摄像头拍摄图片. 当我们点击 upload photos 的时候, 触发下面的代码就可以开始选择图片了
ImagePicker.showImagePicker({
title: null,
cancelButtonTitle: 'cancel',
allowsEditing: true,
chooseFromLibraryButtonTitle: 'choose from camera roll',
takePhotoButtonTitle: type==='video'?null:'open camera',
mediaType: type,
noData: true,
quality: 0.5,
videoQuality: 'medium',
storageOptions: {
skipBackup: true,
cameraRoll: true,
waitUntilSaved: true,
},
}, (response) => {
if (!response.didCancel && !response.error) {
//可以在这里上传图片了
this.startUpload(response);
}
return null;
});
}
当图片选择完毕之后, 就会触发this.startUpload(response); 了, 下面就是如何处理图片上传阿里云的部分了。 在上传文件到阿里云oss 之前呢 需要从Oss获取几个配置项,OSSAccessKeyId,Signature,key, police, 可以看下Oss 文档,这个需要你自己搞定啦。
startUpload(response){
const uploadMediaData = new FormData();
uploadMediaData.append('OSSAccessKeyId', accessKeyId);
uploadMediaData.append('policy', policy);
uploadMediaData.append('Signature', signature);
uploadMediaData.append('key', key);
uploadMediaData.append('success_action_status', 201);
uploadMediaData.append('file', {
uri: response.uri,
type: 'multipart/form-data',
name: response.fileName,
});
// 上传成功
successResponse = (xhr) => {
let returnKey = xhr.responseText.match(/<Key>([^<]*)<\/Key>/)[1];
//这个key 就是你上传文件在oss 的地址了,
};
//上传失败
failResponse = () => {
// to do
};
//开始上传
const OSS_UPLOAD_URI = 'http://xxxxx.oss-us-east-1.aliyuncs.com'
futch(OSS_UPLOAD_URI, {
method: 'POST',
body: uploadMediaData,
extra: null,
}, (progressEvent) => {
// progress 就是上穿的进度, 更新 state 里面的uploadProgress
const progress = (progressEvent.loaded / progressEvent.total);
this.setState({
uploadProgress: progress,
})
}, (xhr) => successResponse(xhr), failResponse)
.then((res) => console.log(res), (err) => console.log('error' + err));
}
//这个方法就是具体上传的代码了
futch = (url, opts = {}, onProgress, successResponse, failResponse) => {
return new Promise((res, rej) => {
let xhr = new XMLHttpRequest();
xhr.open(opts.method || 'get', url);
for (let k in opts.headers || {})
xhr.setRequestHeader(k, opts.headers[k]);
xhr.onload = e => res(e);
xhr.onreadystatechange = (e) => {
if (xhr.readyState !== 4) {
return;
}
//阿里云的状态码201 才有返回的信息
if (xhr.status === 201) {
xhr.extra = opts.extra;
successResponse(xhr);
} else {
xhr.extra = opts.extra;
failResponse(xhr);
}
};
xhr.onerror = rej;
if (xhr.upload && onProgress)
xhr.upload.onprogress = onProgress;
xhr.setRequestHeader('Content-Type', 'multipart/form-data');
xhr.send(opts.body);
});
}
如果一切都ok 的话, 这个时候在上传的过程中就应该出现进度条了,
上面提到了,this.state.uploadProgress 是用来存储上传进度的, 我们就利用这个作为进度条的数据源了, 因为我们用的是圆形的进度条,这里需要另外一个库, ' react-native-progress'.
import ProgressCircle from 'react-native-progress/Circle';
//render 的时候只要把this.state.uploadProgress 丢进去就行了
<ProgressCircle size={30}
showsText={true}
size={100}
progress={uploadProgress}
color={‘#32CDFF’}
thickness={4}
borderWidth={2}
style={styles.progressCircle}
/>
这里特别提出一下,oss 的上传成功的返回代码是201。这样整个过程就结束了, 其中有些细节没提出来,需要大家自己完善,但是大概的流程应该都写出来了. 希望对大大家有用。