React Native 开发APP_react-native-image-resizer-程序员宅基地

技术标签: react native  

记录一下项目中主要用到的技术点吧~

一.电子签名的显示,文件存储到手机,上传

电子签名用到的组件: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);
          });
      });
  }

 

三. 手势系统运用:动态改变scrollview 的滑动方向

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({
});

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Rqlinna/article/details/105960196

智能推荐

Redis为什么变慢了?一文讲透如何排查Redis性能问题 | 万字长文_redis 3.0.5 内存超5g后写入速度慢-程序员宅基地

文章浏览阅读396次。Redis 作为优秀的内存数据库,其拥有非常高的性能,单个实例的 OPS 能够达到 10W 左右。但也正因此如此,当我们在使用 Redis 时,如果发现操作延迟变大的情况,就会与我们的预期不符。你也许或多或少地,也遇到过以下这些场景:在 Redis 上执行同样的命令,为什么有时响应很快,有时却很慢?为什么 Redis 执行 SET、DEL 命令耗时也很久?为什么我的 Redis 突然慢了一波,之后又恢复正常了?为什么我的 Redis 稳定运行了很久,突然从某个时间点开始变慢了?如果你并不清楚 _redis 3.0.5 内存超5g后写入速度慢

提高对C++的认识_对c++的认知-程序员宅基地

文章浏览阅读1k次。C++中有很多 "东西":C,重载,面向对象,模板,例外,名字空间。这么多东西,有时让人感到不知所措。怎么弄懂所有这些东西呢?C++之所以发展到现在这个样子,在于它有自己的设计目标。理解了这些设计目标,就不难弄懂所有这些东西了。C++最首要的目标在于:· 和C的兼容性。很多很多C还存在,很多很多C程序员还存在。C++利用了这一基础,并建立在 ---- 我是指 "平衡在" ---- 这一基础_对c++的认知

软件项目管理课程设计-数字化校园学工信息系统-程序员宅基地

文章浏览阅读2w次,点赞67次,收藏594次。数字化校园学工信息系统小组成员 分工明细:目录一、引言 31.1编写目的 31.2 背景 31.3定义 41.4 参考资料 4二、项目概述 42.1 项目目标 42.2产品目..._软件项目管理课程设计

计算机操作系统实验报告:进程同步与互斥_进程同步与互斥实验总结-程序员宅基地

文章浏览阅读1.1k次,点赞3次,收藏10次。进程同步与互斥。_进程同步与互斥实验总结

vue-实现一个购物车结算页面_vue写购物车界面选择不同尺码对应的价格-程序员宅基地

文章浏览阅读1.8k次。这是路由之间的跳转,传递值最好采用传参,而不是用$emit和$on,不起作用如果实在一个页面中的兄弟组件,可以使用$emit和$on中间件,eventBus.js 放在components目录下面图片路径 static/img模拟数据/static/data.json{"status":1,"result":{"totalMoney":59,"list":[{"pr..._vue写购物车界面选择不同尺码对应的价格

【bandgap】无运放带隙基准电路_不用运放的基准-程序员宅基地

文章浏览阅读605次。M6,M7,Q3支路为M3,M4提供偏置电压,同时起负反馈作用,使节点①电压等于节点②电压。假设节点③电压不等于节点⑤电压,如果V⑤>V③,由VBE1<VBE3得到I1<I5,而由VGS3>VGS7得到I1>I5,与前面得到的结论相矛盾,所以,V⑤=V③,I1=I5,VGS1=VGS6,从而得到节点①电压等于节点②电压。因为M3和M4传输同样的电流,漏极电压又相等,它们接在同一个栅极电压上,所以,V④=V③。刚接通电源时,节点⑥为低电平。图2中,M1,M2,M5,M6宽长比的比例为2∶1∶1∶2。_不用运放的基准

随便推点

第二类斯特林数_n等于2时第二类斯特林数这么用啊-程序员宅基地

文章浏览阅读870次。第二类斯特林数定义:第二类Stirling数实际上是集合的一个拆分,表示将n个不同的元素拆分成m个集合的方案数,记为 或者 。和第一类Stirling数不同的是,集合内是不考虑次序的,而圆排列是有序的。常常用于解决组合数学中几类放球模型。描述为:将n个不同的球放入m个无差别的盒子中,要求盒子非空,有几种方案?递推式第二类Stirling数的推导和第一类Stirling数类似,可_n等于2时第二类斯特林数这么用啊

Excel中插入柱状图以及在图下方显示数据表_柱状图下面怎么带一个表格-程序员宅基地

文章浏览阅读2.1w次。在Sheet中插入柱状图在Excel 中, 有如下数据:上面的数据是学生学科分数的统计,第一行是学科第一列是姓名要插入上面数据的柱状图的步骤如下:选中数据单元格, 包含标头点击 “INSERT” (插入)标签页找到柱状图,点击选择需要的样式, 这里选择堆积柱状图, 也就是可以直观看到每个学生的总分统计。插入的柱状图的效果如下:柱状图的样式有很多种, 除了堆积柱状图之外, 还有簇型、百分比以及三维等, 详细的图的类型有。图表标题鼠标点击图表标题可以直接进行编辑,如下图_柱状图下面怎么带一个表格

log4j升级至log4j2_log4j转log4j2-程序员宅基地

文章浏览阅读1.3w次,点赞5次,收藏24次。本文主要内容包含:实现log4j升级至log4j2,并实现日志自动删除的操作步骤以及注意事项。一、升级原因:log4j存在天然缺陷:log4j采用同步输出模式,当遇到高并发&amp;日志输出过多情况,可能导致线程阻塞,消耗时间过大log4j无法实现自动删除按照日期产生的日志,现有项目都采用定时脚本删除日志。通过调研,log4j2采用异步输出,并且能通过配置实现自动删除日志..._log4j转log4j2

快速恢复Windows 2000/XP遗忘的管理员密码 _windowsadministrator删除了怎么恢复-程序员宅基地

文章浏览阅读881次。  一、删除SAM文件,清除Administrator账号密码  Windows 2000所在的Winnt/System32/Config目录下有个SAM文件(即账号密码数据库文件),它保存了Windows 2000中所有的用户名和密码。当你登录的时候,系统就会把你键入的用户名和密码,与SAM文件中的加密数据进行校对,如果两者完全符合,则会顺利进入系统,否则将无法登录,因此我们可以使用删除SAM文_windowsadministrator删除了怎么恢复

前端工作经验总结以及技术分享_前端技术分享-程序员宅基地

文章浏览阅读8.6k次,点赞74次,收藏324次。uniapp H5 公众号微信自定义分享qq,微信带图片标题内容__揽的博客-程序员宅基地js获取当前日期,并将其格式化为YYYY-MM-DD,并且自定义返回__揽的博客-程序员宅基地_js获取当前日期并格式化(成功最详细版本,自定义传参失败,跳转出现空白页面,校验文件失败)微信小程序扫码跳转小程序指定页面保姆级教程__揽的博客-程序员宅基地_小程序二维码校验文件(巨好使,详细,解析URl,URl自定义传参)js URl中快速自定义传参,并且实现参数解析 修改 和新增,替换功能__揽的博客-程序员宅基地。_前端技术分享

android webview访问本地文件_android webview 本地文件-程序员宅基地

文章浏览阅读3.1k次。android webview访问本地文件_android webview 本地文件

推荐文章

热门文章

相关标签