记录一下项目中主要用到的技术点吧~
电子签名用到的组件:react-native-signature-capture
写文件react-native-fs
上传用到的组件react-native-fetch-blob
import React, { Component, Fragment } from "react";
import { StyleSheet, View, TextInput, Text,TouchableOpacity, Image, FlatList, Dimensions,
} from "react-native";
import { common_url, fetchRequest } from "../../utils/request";
import Dialog, { DialogButton, DialogContent, DialogFooter, DialogTitle } from "react-native-popup-dialog";
import SignatureCapture from "react-native-signature-capture";
import RNFetchBlob from "react-native-fetch-blob";
var RNFS = require('react-native-fs');
export default class SignConstract extends Component {
constructor(props) {
super(props);
this.state = {
visible:false,
contract:"",
signImg:"",
};
}
//签名
_onSaveEvent(result) {
if(result.encoded!=undefined){
this.setState({
signImg:result.encoded, //result.encoded base64编码,用于签名图片的显示
})
}
var timestamp = (new Date()).getTime();
const path = RNFS.PicturesDirectoryPath + '/'+timestamp+'signature.png';
// write the file
RNFS.writeFile(path, result.encoded, 'base64')
.then((success) => {
console.log('存储在手机的文件路径path', path);
})
.catch((err) => {
console.log(err.message);
});
//转化后的本地路径
this.upload(result.pathName)
}
//上传文件
upload(pathName){
DeviceStorage.get("ownerId").then((ownerId) => {
var declareId ="1";
let body = [{
name: "declareId", data:declareId
},
{
name: "sign",
filename: "测试",
type: "image/png",
data: RNFetchBlob.wrap(pathName)
}];
RNFetchBlob.fetch("POST", common_url+"hserp_owners/participateSing", {
// 上传图片要设置Header
"Content-Type":"multipart/form-data",
}, body)
.uploadProgress((written, total) => {
// 本地查找进度
})
.progress((received, total) => {
let perent = received / total;
console.log("上传进度打印", perent);
})
.then((response) => response.json())
.then((response) => {
console.log("上传信息返回", response);
})
.catch((error) => {
// 错误信息
console.log(error);
});
});
}
//保存签名
saveSign() {
this.refs["sign"].saveImage();
}
//清除签名
resetSign() {
this.refs["sign"].resetImage();
}
render() {
return (
<View style={styles.container}>
<View style={{ flex: 1 }}>
<View style={styles.content}>
<View style={styles.rowBorder}>
<TouchableOpacity style={styles.rowContent} onPress={() => {
this.setState({
visible: true
});
}}>
<Text style={{color:theme.color}}>签名:</Text>
<Image source={{ uri: "data:image/jpg;base64," + this.state.signImg }} style={styles.img}/>
</TouchableOpacity>
</View>
</View>
{/*确认*/}
<Dialog
width={0.9}
height={0.7}
visible={this.state.visible}
footer={
<DialogFooter>
<DialogButton
text="取消"
onPress={() => {
this.setState({
visible: false
});
}}
/>
<DialogButton
text="确定"
onPress={() => {
this.setState({
visible: false
}, () => {
this.saveSign();
});
}}
/>
</DialogFooter>
}
dialogTitle={<DialogTitle title="签名确认"/>}>
<DialogContent style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
<SignatureCapture
ref="sign"
style={{ flex: 1 }}
minStrokeWidth={5}
maxStrokeWidth={5}
showNativeButtons={false}
saveImageFileInExtStorage={true} //是否存储在手机
onSaveEvent={this._onSaveEvent.bind(this)}
/>
</View>
</DialogContent>
</Dialog>
<View style={styles.btn}>
<Text style={styles.white}
onPress={() => {
if(!this.state.signImg){
this.refs.toast.show("请签名", 4000);
return false
}else{
Actions.Renovation({sign:this.state.path})
}
}}>下一步</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: theme.gray
},
});
用到的组件:react-native-image-resizer,上传前自己用promise做了个处理压缩多图
import React, { Component } from "react";
import {StyleSheet, View, ScrollView, TextInput, Text, TouchableOpacity, Image, FlatList, Dimensions, DeviceEventEmitter, ImageBackground} from "react-native";
import { common_url, fetchRequest } from "../../utils/request";
import RNFetchBlob from "react-native-fetch-blob";
import ImageResizer from 'react-native-image-resizer';
export default class RepaireApply extends Component {
constructor(props) {
super(props);
this.state = {
imgArr: [],
typeArr: [],
date: "",
total: "",
imgId: ""
};
}
componentWillMount() {
this.getList();
this.deEmitter = DeviceEventEmitter.addListener("left", (a) => {
this.setState({
imgArr: a
});
});
}
componentWillUnmount() {
this.deEmitter.remove();
}
async save() {
DeviceStorage.get("ownerId").then(async(ownerId) => {
let arr = [];
this.state.imgArr.map((item, index) => {
arr.push(ImageResizer.createResizedImage(item, 100, 100, "PNG", 100 ))
})
let arr2 = [];
let result=await Promise.all(arr)
result.map((item, index) => {
var obj = {
name: "picture" + index,
filename: "picture" + item.name,
type: "image/png",
data: RNFetchBlob.wrap(item.uri)
};
arr2.push(obj);
});
arr2.push({
name: "request", data: this.state.requests
}, {
name: "size", data: this.state.imgArr.length + ""
});
RNFetchBlob.fetch("POST", common_url + "hserp_owners/repairMaintenance", {
"Content-Type": "multipart/form-data"
}, arr2)
.uploadProgress((written, total) => {
})
.progress((received, total) => {
})
.then((response) => response.json())
.then((response) => {
})
.catch((error) => {
// 错误信息
console.log(error);
});
});
}
import React, { Component } from "react";
import { StyleSheet, View,Text, TouchableOpacity,ScrollView, PanResponder} from "react-native";
import { fetchRequest } from "../../utils/request";
var Dimensions = require("Dimensions");
export default class ParkSpace extends Component {
constructor(props) {
super(props);
this.state = {
horizontal:false
};
}
componentWillMount() {
this._panResponder = PanResponder.create({
// 要求成为响应者
// nativeEvent
// gestureState dx - 从触摸操作开始时的累计横向路程 dy - 从触摸操作开始时的累计纵向路程
//表示是否成为滑动事件的劫持者,如果返回是,则不会把滑动事件传递给它的子元素。
onStartShouldSetPanResponder: (evt, gestureState) => false,
//表示是否成为事件的劫持者,如果返回是,则不会把事件传递给它的子元素
onStartShouldSetPanResponderCapture: (evt, gestureState) => false,
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
onStartShouldSetResponderCapture: (evt)=> true,
VonMoveShouldSetResponderCapture: (evt)=> true,
//开始手势操作
onPanResponderGrant: (evt, gestureState) => {
// this._highlight();
this.setState({
horizontal:true
})
},
//触摸点移动
onPanResponderMove: (evt, gestureState) => {
this.state.ScreenWidth,gestureState.moveX,)
console.log(`gestureState.moveX : ${gestureState.moveX } gestureState.moveY : ${gestureState.moveY }`);
if(gestureState.moveX<this.state.ScreenWidth){
//动态改变
this.setState({
horizontal:true
})
}else{
this.setState({
horizontal:false
})
}
},
//用户放开了所有的触摸点,且此时视图已经成为了响应者
onPanResponderRelease: (evt, gestureState) => {
},
//另一个组件已经成为了新的响应者,所以当前手势将被取消
onPanResponderTerminate: (evt, gestureState) => {
},
});
}
show(typeId,carType, price,number) {
Actions.CartFee({"typeId":typeId,"carType": carType, "carPrice": price,"number":number,area:this.state.area });
}
render() {
return (
<View style={{display:"flex",height:"100%"}}>
<ScrollView style={{flex:1}}
horizontal={this.state.horizontal} //水平
showsHorizontalScrollIndicator={true}
showsVerticalScrollIndicator={true}
removeClippedSubviews={false}
overScrollMode="always">
<View style={{width:this.state.parkWidth,height:this.state.parkHeight,backgroundColor: "#00ff00"}}
{...this._panResponder.panHandlers}>
{this.state.cars.map((item) => {
return (
<TouchableOpacity style={{ position: "absolute", left: (item.abscissa_y - 1) * this.state.cellWidth, top: (item.abscissa_x - 1) * this.state.cellHeight }}
key={item.id}
onPress={() => {
if (item.state != "3") {
this.refs.toast.show("该车位已租售,请重新选择", 4000
return false;
} else {
this.show(item.type_id[0],item.type_id[1], item.price,item.parking_number);
}
}}
>
<View style={{ width:60,
height:30,
backgroundColor: "#848484",
borderColor: "#fff",
borderBottomWidth:2,
borderTopWidth:2,
borderLeftWidth:2,
transform: [{ rotate: item.angle+"deg"}]
}}>
<Text style={styles.zhu}>▎</Text>
<Text style={styles.zhu}>▎</Text>
<Text style={{position:"absolute", top:"30%", left:"30%", color:"white", fontSize:8,transform: [{ rotate: item.angle+"deg"}]}}>{item.parking_number}</Text>
<Text style={styles.tang}>▲</Text>
</View>
</TouchableOpacity>
);
})}
</View>
</ScrollView>
<Toast
ref="toast"
style={{ backgroundColor:theme.toastColor}}
position='center'
fadeInDuration={theme.fadeInDuration}
fadeOutDuration={theme.fadeOutDuration}
opacity={0.7}
textStyle={{ color: "white" }}
/>
</View>
);
}
}
const styles = StyleSheet.create({
});