react-native 画笔(写字板、手写板)--2

目前已完成功能包括线条标注箭头、圆圈、画笔、矩形、粗细、颜色、撤销、清空、保存。移动图片,标注文字暂时未完成,还有后期的一些功能未完善,如标注后,点击改标注可以随意修改其大小、位置、方向等,后面有时间再研究下。

其中箭头是最麻烦的,其他功能一旦熟悉花的时间不多,但是光是箭头花了差不多五天的时间,因为没有思路,想过用svg rotate旋转,后来发现也是不太好实现,除了触摸点,箭头三角形其他点也是需要旋转一样的角度,这个不太好算。
后面经过分析通过三角函数将三角形箭头的两侧的点算出来,算的三角形两个侧边点在屏幕的坐标,就可以做出来了。当然,箭头三角形是等腰三角形,要是想要搞成像微信截图那样的箭头,需要自己深入计算一下,思路一样,SVG不是很熟悉的可以看一下我之前写的这篇https://www.jianshu.com/p/ef91237a89a4,也可以自己上菜鸟教程简单的练一下再上手。先上效果图后上代码。

111571643003776_.pic.jpg

111561643003775_.pic.jpg
111621643003922_.pic.jpg

案例:

复制以下代码,添加安装react-native-svg、react-native-view-shot 、替换里面的图片,新建一个页面就可以查看效果

import React, {Component} from 'react';
import {View, Text, Image, StyleSheet, PanResponder, TouchableOpacity, TextInput} from 'react-native'
import Svg, {Path, Rect, Circle, Ellipse, Line} from "react-native-svg";
// import Util from "../common/util";
// import MyToast from "../common/MyToast";
import ViewShot from "react-native-view-shot";

// 这两个是为了写字板样式若是有什么边距问题,有padding或margin的加上去,以屏幕手势起始点开始,如果没有边距问题都赋值为0就好
let marginY = 50  //头部导航height 50
let marginX = 0  // 图片与父盒子距离 0

class Comp3 extends Component {
    constructor(props) {
        super(props);
        this.allPathPointsAsign = ''  //所有点的合并
        this.allPathPointsList = []   //所有路径点数组、用来操作撤销
        this.state = {
            /**画笔**/
            drawPath: '',

            /**规格**/
            size_id: 0,
            color_id: 0,
            currentSize: 3,   //默认线条粗细
            currentColor: '#FF0000', //默认线条颜色
            line_list: [
                {size: 3, selectColor: ''},
                {size: 6, selectColor: ''},
                {size: 9, selectColor: ''},
            ],
            color_list: ['#FF0000', '#000000', '#00FF00', '#0000FF', '#FF7700', '#FF00FF', '#00FFFF', '#000000', '#FF0000', '#00FF00', '#0000FF', '#FF7700', '#FF00FF', '#00FFFF', '#FF00FF', '#00FFFF',],

            /**矩形**/
            rectWidth: 0,
            rectHeight: 0,

            /**椭圆**/
            circleWidth: 0,
            circleHeight: 0,

            /**箭头*/
            arrowPath: '',
            arrowSPath: '',

            /**所有操作集合数组**/
            myAllList: [],

            inputStyle: {
                left: 0,
                top: 0,
            },
            inputWidth: 0,
            inputHeight: 0,

            isShowLineSize: false,
            isShowColorful: false,
            isDrawing: false,
            drawType: 4,
            angle: 0,
            image_url: this.props.image_url,
        }
    }


    UNSAFE_componentWillMount() {
        this._panResponderDrawLine = PanResponder.create({
            // 要求成为响应者:
            onStartShouldSetPanResponder: (evt, gestureState) => true,
            onStartShouldSetPanResponderCapture: (evt, gestureState) => false,
            onMoveShouldSetPanResponder: (evt, gestureState) => false,
            onMoveShouldSetPanResponderCapture: (evt, gestureState) => false,

            onPanResponderGrant: (evt, gestureState) => {
                this.isMove = false
                this._onPanResponderGrant(evt, gestureState)
            },

            onPanResponderMove: (evt, gestureState) => {
                console.log('画画夺权')
                this.isMove = true
                this._onPanResponderMove(evt, gestureState)
            },

            onPanResponderTerminationRequest: (evt, gestureState) => true,
            onPanResponderRelease: (evt, gestureState) => {
                if (this.isMove) {   //判断是否是移动后,因为有些只是点一下,但是并没有画线也push到了数组
                    this._onPanResponderRelease(evt, gestureState)
                }

            },

            onPanResponderTerminate: (evt, gestureState) => {
            },

            onShouldBlockNativeResponder: (evt, gestureState) => {
                return true;
            },
        })

        this._panResponderChange = PanResponder.create({
            // 要求成为响应者:
            onStartShouldSetPanResponder: (evt, gestureState) => true,
            onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
            onMoveShouldSetPanResponder: (evt, gestureState) => true,
            onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,

            onPanResponderGrant: (evt, gestureState) => {
                //在这里点的时候激活一个矩形边框,类似微信截图的(当然这个边框是需要自己算的它的长宽高和距离顶部、左边位置)
                console.log('点击==激活===========', evt, gestureState)
            },

            onPanResponderMove: (evt, gestureState) => {
                //上方激活后,可以在这里变形这个图形rotate、scale、translate、变形完了添加到数组里面的属性遍历出来即可
                console.log('移动夺权移动变形的在这里添加,如rotate、scale、translate等加到数组属性里')

            },

            onPanResponderTerminationRequest: (evt, gestureState) => true,
            onPanResponderRelease: (evt, gestureState) => {
                console.log('放手======onPanResponderRelease==========', this.pathRef)
            },

            onPanResponderTerminate: (evt, gestureState) => {
            },

            onShouldBlockNativeResponder: (evt, gestureState) => {
                return true;
            },
        })
    }

    _onPanResponderGrant(evt, gestureState) {
        let drawType = this.state.drawType
        this.setState({
            isDrawing: true
        })

        /**画线**/
        if (drawType === 4) {
            console.log('手指开始接触====', evt.nativeEvent)
            let tempfirstX = evt.nativeEvent.pageX - marginX
            let tempFirstY = evt.nativeEvent.pageY - marginY
            this.firstPoint = ` M${tempfirstX} ${tempFirstY}`
            this.allPathPointsAsign = this.firstPoint
        }

        /**矩形**/
        if (drawType === 5) {
            console.log('矩形开始接触====', evt.nativeEvent)
            this.rectFirstPageX = evt.nativeEvent.pageX - marginX    //减去marginX,marginY 是为了手势起始点要以图片左上角开始
            this.rectFirstPageY = evt.nativeEvent.pageY - marginY
            this.setState({
                rectFirstPageX: this.rectFirstPageX,
                rectFirstPageY: this.rectFirstPageY,
                rectWidth: 0,   //把上一次的矩形宽高清零
                rectHeight: 0,
            })
        }

        /**椭圆**/
        if (drawType === 3) {
            console.log('椭圆开始接触====', evt.nativeEvent)
            this.circleFirstPageX = evt.nativeEvent.pageX - marginX    //减去marginX,marginY 是为了手势起始点要以图片左上角开始
            this.circleFirstPageY = evt.nativeEvent.pageY - marginY
            this.setState({
                circleFirstPageX: this.circleFirstPageX,
                circleFirstPageY: this.circleFirstPageY,
                circleWidth: 0,   //把上一次的矩形宽高清零
                circleHeight: 0,
            })
        }

        /**箭头**/
        if (drawType === 2) {
            // console.log('箭头开始接触====', evt.nativeEvent)
            this.arrowFirstPageX = evt.nativeEvent.pageX - marginX    //减去marginX,marginY 是为了手势起始点要以图片左上角开始
            this.arrowFirstPageY = evt.nativeEvent.pageY - marginY

            let str = ` M${this.arrowFirstPageX} ${this.arrowFirstPageY}`
            console.log('str====', str)
            this.firstArrowPoint = str
            this.setState({
                arrowPath: '',
                arrowSPath: '',
            })
        }

        /**输入文本**/
        if (drawType === 1) {
            this.touchPageX = evt.nativeEvent.pageX - marginX    //减去marginX,marginY 是为了手势起始点要以图片左上角开始
            this.touchPageY = evt.nativeEvent.pageY - marginY
            // return
            // console.log('this.touchPageX',this.touchPageX,'this.touchPageY',this.touchPageY)
        }
    }

    _onPanResponderMove(evt, gestureState) {
        let drawType = this.state.drawType

        /**画线**/
        if (drawType === 4) {
            let pointX = evt.nativeEvent.pageX - marginX
            let pointY = evt.nativeEvent.pageY - marginY
            let point = ` L${pointX} ${pointY}`
            this.allPathPointsAsign += point
            // console.log('point====', this.allPathPointsAsign)
            let drawPath = this.allPathPointsAsign   //一次性画了之后存到一个数组,目的是为了后面的撤销操作

            let tempId = this.state.size_id            //在移动的时候才给他赋值颜色/线条。而不是在选择颜色的时候就直接赋值改变线条的颜色,
            let tempColorId = this.state.color_id          //若是在选择颜色/线条的时候直接赋值,会改变前一次画好的线的颜色/线条,不可取
            let currentSize = this.state.line_list[tempId].size  //使用临时粗细是为了在切换线条大小的时候,前一次画好的线条粗细不会发生变化
            let currentColor = this.state.color_list[tempColorId]  //使用临时颜色是为了在切换线条大小的时候,前一次画好的线条颜色不会发生变化

            this.setState({
                currentSize,   //当前线的粗细
                currentColor,   //当前线的颜色
                drawPath,
            })
        }

        /**矩形**/
        if (drawType === 5) {
            // console.log('矩形move====', evt.nativeEvent.pageX,'===',evt.nativeEvent.pageY)
            let pointX = evt.nativeEvent.pageX - marginX
            let pointY = evt.nativeEvent.pageY - marginY
            let rectWidth = pointX - this.rectFirstPageX
            let rectHeight = pointY - this.rectFirstPageY
            console.log('矩形宽高===', rectWidth, rectHeight)

            let tempId = this.state.size_id            //在移动的时候才给他赋值颜色/线条。而不是在选择颜色的时候就直接赋值改变线条的颜色,
            let tempColorId = this.state.color_id          //若是在选择颜色/线条的时候直接赋值,会改变前一次画好的线的颜色/线条,不可取
            let currentSize = this.state.line_list[tempId].size  //使用临时粗细是为了在切换线条大小的时候,前一次画好的线条粗细不会发生变化
            let currentColor = this.state.color_list[tempColorId]  //使用临时颜色是为了在切换线条大小的时候,前一次画好的线条颜色不会发生变化

            // 这部分代码在以创建矩形时初始坐标为原点(0,0),在向右或者向上框选的时候,是负值的,此时矩形时宽或者高是负数的,不会显示
            // 所以在将宽高转为整数的时候,这时候将宽高的绝对值作为初始值坐标的增减,这样才能实现宽高的增减

            let newPageX = this.rectFirstPageX + rectWidth
            let newPageY = this.rectFirstPageY + rectHeight
            if (rectHeight < 0) {
                rectHeight = Math.abs(rectHeight)   //高为绝对值
                this.setState({
                    rectFirstPageY: newPageY    //重新定位原点Y坐标
                })
            }
            if (rectWidth < 0) {
                rectWidth = Math.abs(rectWidth)  //宽为绝对值
                this.setState({
                    rectFirstPageX: newPageX,  //重新定位原点X坐标
                })
            }
            this.setState({
                rectWidth,
                rectHeight,
                currentSize,   //当前线的粗细
                currentColor,   //当前线的颜色
            })
        }

        /**椭圆**/
        if (drawType === 3) {
            console.log('椭圆正在画====', evt.nativeEvent)
            let pointX = evt.nativeEvent.pageX - marginX
            let pointY = evt.nativeEvent.pageY - marginY
            let circleWidth = pointX - this.circleFirstPageX
            let circleHeight = pointY - this.circleFirstPageY
            console.log('矩形宽高===', circleWidth, circleHeight)

            let tempId = this.state.size_id            //在移动的时候才给他赋值颜色/线条。而不是在选择颜色的时候就直接赋值改变线条的颜色,
            let tempColorId = this.state.color_id          //若是在选择颜色/线条的时候直接赋值,会改变前一次画好的线的颜色/线条,不可取
            let currentSize = this.state.line_list[tempId].size  //使用临时粗细是为了在切换线条大小的时候,前一次画好的线条粗细不会发生变化
            let currentColor = this.state.color_list[tempColorId]  //使用临时颜色是为了在切换线条大小的时候,前一次画好的线条颜色不会发生变化

            // 这部分代码在以创建矩形时初始坐标为原点(0,0),在向右或者向上框选的时候,是负值的,此时矩形时宽或者高是负数的,不会显示
            // 所以在将宽高转为整数的时候,这时候将宽高的绝对值作为初始值坐标的增减,这样才能实现宽高的增减

            let newPageX = this.circleFirstPageX + circleWidth
            let newPageY = this.circleFirstPageY + circleHeight
            if (circleHeight < 0) {
                circleHeight = Math.abs(circleHeight)   //高为绝对值
                this.setState({
                    circleFirstPageY: newPageY    //重新定位原点Y坐标
                })
            }
            if (circleWidth < 0) {
                circleWidth = Math.abs(circleWidth)  //宽为绝对值
                this.setState({
                    circleFirstPageX: newPageX,  //重新定位原点X坐标
                })
            }
            this.setState({
                circleWidth,
                circleHeight,
                currentSize,   //当前线的粗细
                currentColor,   //当前线的颜色
            })
        }

        /**箭头**/
        if (drawType === 2) {
            let pointX = evt.nativeEvent.pageX - marginX
            let pointY = evt.nativeEvent.pageY - marginY
            let y = 0, x = 0
            if (pointY > this.arrowFirstPageY) {
                y = -(pointY - this.arrowFirstPageY)    //如果超过原始点就为 -y  即在y的负半轴
            }
            if (pointY < this.arrowFirstPageY) {
                y = this.arrowFirstPageY - pointY    //如果小于原始点就为 y  即在y的正半轴
            }
            if (pointX > this.arrowFirstPageX) {
                x = pointX - this.arrowFirstPageX    //如果超过原始点就为 x  即在x的正半轴
            }
            if (pointX < this.arrowFirstPageX) {
                x = -(this.arrowFirstPageX - pointX)    //如果小于原始点就为 -x  即在x的负半轴
            }
            let k = y / x    //直线(箭头)的斜率
            if (!k) {
                return
            }
            let c1 = Math.sqrt(Math.pow(Math.abs(x), 2) + Math.pow(Math.abs(y), 2))   //这是整个直线(箭头)的长度
            let radian = Math.atan(Math.abs(k))   //主线条与X轴的弧度值
            let angle = radian * (180 / Math.PI)   //主线条与X轴的夹角    角度 = 弧度值 * (180/π)

            let {a, b} = this.autoSize(c1)   //三角形自动大小
            // console.log('a====>>>',a,'b====>>>',b,)
            let c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2))  //根据勾股定理计算斜边,即三角形侧边长
            let a1, b1    //三角形侧边点与触摸点的宽或高
            let newAngle = 45 - angle   //根据相似三角形求得夹角
            a1 = Math.sin(Math.PI / (180 / newAngle)) * c   //顺时针方向三角形第一个侧边点与触摸点的距离宽,用来计算第一个侧边点x坐标
            b1 = Math.cos(Math.PI / (180 / newAngle)) * c   //顺时针方向三角形第一个侧边点与触摸点的距离高,用来计算第一个侧边点y坐标

            // console.log('x、y===>>>', x, y)
            // console.log('k===>>>', k)
            // console.log('angle===>>>', angle)   //线与x轴的夹角
            let {twoPoints, tangle} = this.drawArrowPath(pointX, pointY, a1, b1, k, angle)
            let finalPath = twoPoints + tangle

            console.log('finalPath===>>>>', finalPath)
            console.log('tangle===>>>>', tangle)

            this.arrowPath = finalPath
            this.arrowSPath = tangle
            let tempId = this.state.size_id            //在移动的时候才给他赋值颜色/线条。而不是在选择颜色的时候就直接赋值改变线条的颜色,
            let tempColorId = this.state.color_id          //若是在选择颜色/线条的时候直接赋值,会改变前一次画好的线的颜色/线条,不可取
            let currentSize = this.state.line_list[tempId].size  //使用临时粗细是为了在切换线条大小的时候,前一次画好的线条粗细不会发生变化
            let currentColor = this.state.color_list[tempColorId]  //使用临时颜色是为了在切换线条大小的时候,前一次画好的线条颜色不会发生变化
            this.setState({
                currentSize,   //当前线的粗细
                currentColor,   //当前线的颜色
                arrowPath: finalPath,
                arrowSPath: tangle
            })
        }
    }

    autoSize(c1) {
        let a = 25, b = 12.5   //三角形三边
        let size_id = this.state.size_id
        console.log('size_id====', size_id)
        if (c1 < 80 || size_id === 0) {
            a = 10;
            b = 10;
        } else if (c1 < 120 || size_id === 1) {
            a = 15;
            b = 15;
        } else if (c1 < 150 || size_id === 1) {
            a = 25;
            b = 12.5;
        }
        return {a, b}
    }

    drawArrowPath(pointX, pointY, a1, b1, k, angle) {
        let tangle   //定义三角形
        let firstM1  // 主体斜宽线与三角形连接点1
        let firstM2  // 主体斜宽线与三角形连接点2
        if (pointY < this.arrowFirstPageY && pointX > this.arrowFirstPageX) {   //第一象限
            tangle = ` M${pointX} ${pointY} L${pointX - a1} ${pointY + b1} L${pointX - b1} ${pointY - a1}`
            firstM1 = ` L${pointX - (a1 / 2)} ${pointY + (b1 / 2)}`
            firstM2 = ` L${pointX - (b1 / 2)} ${pointY - (a1 / 2)}`
        }
        if (pointY < this.arrowFirstPageY && pointX < this.arrowFirstPageX) {   //第二象限
            tangle = ` M${pointX} ${pointY} L${pointX + b1} ${pointY - a1} L${pointX + a1} ${pointY + b1}`
            firstM1 = ` L${pointX + (b1 / 2)} ${pointY - (a1 / 2)}`
            firstM2 = ` L${pointX + (a1 / 2)} ${pointY + (b1 / 2)}`
        }
        if (pointY > this.arrowFirstPageY && pointX < this.arrowFirstPageX) {   //第三象限
            tangle = ` M${pointX} ${pointY} L${pointX + a1} ${pointY - b1} L${pointX + b1} ${pointY + a1}`
            firstM1 = ` L${pointX + (a1 / 2)} ${pointY - (b1 / 2)}`
            firstM2 = ` L${pointX + (b1 / 2)} ${pointY + (a1 / 2)}`
        }
        if (pointY > this.arrowFirstPageY && pointX > this.arrowFirstPageX) {   //第四象限
            tangle = ` M${pointX} ${pointY} L${pointX - b1} ${pointY + a1} L${pointX - a1} ${pointY - b1}`
            firstM1 = `L${pointX - (b1 / 2)} ${pointY + (a1 / 2)}`
            firstM2 = `L${pointX - (a1 / 2)} ${pointY - (b1 / 2)}`
        }

        // firstM1 + `M${pointX - b1} ${pointY + a1} L${pointX} ${pointY}` +  firstM2
        if (k === 0 && pointX < this.arrowFirstPageX) {   //在 X 负半轴 上时,即k=0
            tangle = ` M${pointX} ${pointY} L${pointX + a1} ${pointY - b1} L${pointX + a1} ${pointY + b1}`
            firstM1 = `L${pointX + (a1 / 2)} ${pointY - (b1 / 2)}`
            firstM2 = `L${pointX + (a1 / 2)} ${pointY + (b1 / 2)}`
        }
        if (k === 0 && pointX > this.arrowFirstPageX) {  //在 X 正半轴 上时,即k=0
            tangle = ` M${pointX} ${pointY} L${pointX - a1} ${pointY + b1} L${pointX - a1} ${pointY - b1}`
            firstM1 = `L${pointX - (a1 / 2)} ${pointY + (b1 / 2)}`
            firstM2 = `L${pointX - (a1 / 2)} ${pointY - (b1 / 2)}`
        }
        if (angle === 90 && pointY > this.arrowFirstPageY) {  //在 Y 负半轴 上时
            tangle = ` M${pointX} ${pointY} L${pointX - a1} ${pointY - b1} L${pointX + a1} ${pointY - b1}`
            firstM1 = `L${pointX - (a1 / 2)} ${pointY - (b1 / 2)}`
            firstM2 = `L${pointX + (a1 / 2)} ${pointY - (b1 / 2)}`
        }
        if (angle === 90 && pointY < this.arrowFirstPageY) {  //在 Y 正半轴 上时
            tangle = ` M${pointX} ${pointY} L${pointX + a1} ${pointY + b1} L${pointX - a1} ${pointY + b1}`
            firstM1 = `L${pointX + (a1 / 2)} ${pointY + (b1 / 2)}`
            firstM2 = `L${pointX - (a1 / 2)} ${pointY + (b1 / 2)}`
        }
        // console.log('firstM1===', firstM1, 'firstM2===', firstM2,)

        let twoPoints = this.firstArrowPoint + firstM1 + firstM2   //两点一直线
        return {twoPoints, tangle}
    }

    _onPanResponderRelease(evt, gestureState) {
        let drawType = this.state.drawType
        this.setState({
            isDrawing: false
        })
        /**画线**/
        if (drawType === 4) {
            let obj = {
                size_id: this.state.size_id,
                color_id: this.state.color_id,
                path: this.allPathPointsAsign,
                pathType: 'line'
            }
            this.allPathPointsList.push(obj)      //将所有画过的线以及他的粗细、颜色等保存起来
            console.log('this.allPathPointsList====', this.allPathPointsList)
            this.setState({
                myAllList: this.allPathPointsList
            })
        }

        /**矩形**/
        if (drawType === 5) {
            console.log('矩形放开手指====', evt.nativeEvent)
            let obj = {
                size_id: this.state.size_id,
                color_id: this.state.color_id,
                pageX: this.state.rectFirstPageX,
                pageY: this.state.rectFirstPageY,
                rectHeight: this.state.rectHeight,
                rectWidth: this.state.rectWidth,
                pathType: 'rect'
            }
            this.allPathPointsList.push(obj)      //将所有画过的矩形以及他的粗细、颜色等保存起来
            console.log('this.allPathPointsList====', this.allPathPointsList)
            this.setState({
                myAllList: this.allPathPointsList
            })
        }

        /**椭圆**/
        if (drawType === 3) {
            console.log('椭圆完成====', evt.nativeEvent)
            let obj = {
                size_id: this.state.size_id,
                color_id: this.state.color_id,
                pageX: this.state.circleFirstPageX,
                pageY: this.state.circleFirstPageY,
                circleHeight: this.state.circleHeight,
                circleWidth: this.state.circleWidth,
                pathType: 'circle'
            }
            this.allPathPointsList.push(obj)      //将所有画过的矩形以及他的粗细、颜色等保存起来
            console.log('this.allPathPointsList====', this.allPathPointsList)
            this.setState({
                myAllList: this.allPathPointsList
            })
        }

        /**箭头**/
        if (drawType === 2) {
            console.log('箭头完成====', evt.nativeEvent)
            let obj = {
                size_id: this.state.size_id,
                color_id: this.state.color_id,
                arrowPath: this.arrowPath,
                arrowSPath: this.arrowSPath,
                pathType: 'arrow'
            }
            this.allPathPointsList.push(obj)
            this.setState({
                myAllList: this.allPathPointsList
            })
            console.log('myAllList====', this.state.myAllList)
        }

        /**输入文本**/
        if (drawType === 1) {
            // console.log('箭头开始接触====', evt.nativeEvent)
            this.touchPageX = evt.nativeEvent.pageX - marginX    //减去marginX,marginY 是为了手势起始点要以图片左上角开始
            this.touchPageY = evt.nativeEvent.pageY - marginY
            console.log('this.touchPageX', this.touchPageX, 'this.touchPageY', this.touchPageY)
            // if(){
            //
            // }
            let inputStyle = {
                left: this.touchPageX,
                top: this.touchPageY - this.state.inputHeight / 2,
            }
            this.setState({
                inputStyle
            })
        }

    }

    //撤销
    revoke() {
        this.allPathPointsList.pop(1)
        this.setState({
            drawPath: '',  //这是清除已经刚刚画好的
            myAllList: this.allPathPointsList,
            rectWidth: 0,
            rectHeight: 0,
            circleWidth: 0,
            circleHeight: 0,
        })
    }

    //清空
    clearOut() {
        this.allPathPointsList = []
        this.setState({
            drawPath: '',  //这是清除已经刚刚画好的
            myAllList: [],
            rectWidth: 0,
            rectHeight: 0,
            circleWidth: 0,
            circleHeight: 0,
        })
    }

    //保存画板内容
    savePhoto() {
        this.refs.viewShot.capture().then(uri => {
            console.log("do something with ", uri);
            // Util.saveLocalImage(uri,(res)=>{
            //     console.log('保存成功====1111',res)
            //     MyToast.show('图片保存成功');
            // },(err)=>{
            //     MyToast.show('图片保存失败')
            //     console.log('保存失败====',err)
            // })
        });
    }

    //选择线的粗细
    onSelectLineSize(item, id) {
        console.log('选择线条粗细===', item)
        this.setState({
            isShowLineSize: false,
            size_id: id
        })
    }

    //选择颜色id
    onSelectColor(item, id) {
        this.setState({
            isShowColorful: false,
            color_id: id
        })
    }

    //选择绘画类型(操作类型):  0:拖动、1:添加字符、2-5:线条类型、6:粗细、7:色彩
    onSelectDrawType(type) {
        switch (type) {
            case 6 :
                this.setState({isShowLineSize: true});
                break;
            case 7 :
                this.setState({isShowColorful: true});
                break;
            default:
                this.setState({drawType: type});
        }
    }

    _onLayout(e) {
        console.log('_onLayout1===', e.nativeEvent)
        this.setState({
            inputWidth: e.nativeEvent.layout.width,
            inputHeight: e.nativeEvent.layout.height,
        })
    }

    render() {
        let {line_list, isShowColorful, color_list, drawType, isDrawing, image_url} = this.state
        return (
            <View style={styles.container}>
                <View style={{flex: 1, backgroundColor: '#fff'}}>

                    <ViewShot ref="viewShot" options={{format: "jpg", quality: 1.0}} style={{flex: 1}}>
                        <View style={{flex: 1,}} {...this._panResponderDrawLine.panHandlers} >


                            <Image
                                source={require('../../images/default.jpg')}
                                // source={{uri:image_url}}
                                style={{height: '100%', width: '100%', position: 'absolute'}}
                            />
                            <Svg height="100%" width="100%">
                                {
                                    //这是已经存储过的线
                                    this.state.myAllList.map((item, id) => {
                                        return (
                                            item.pathType === 'line' ?
                                                <Path
                                                    ref={ref => this.pathRef = ref}
                                                    key={id}
                                                    d={item.path}
                                                    fill="none"
                                                    strokeLinecap="round"
                                                    stroke={color_list[item.color_id]}
                                                    strokeWidth={line_list[item.size_id].size}
                                                    {...this._panResponderChange.panHandlers}
                                                /> :
                                                item.pathType === 'rect' ?
                                                    <Rect
                                                        key={id}
                                                        x={item.pageX}
                                                        y={item.pageY}
                                                        rx="2"
                                                        ry="2"
                                                        width={item.rectWidth}
                                                        height={item.rectHeight}
                                                        fill="none"
                                                        strokeWidth={line_list[item.size_id].size}
                                                        stroke={color_list[item.color_id]}
                                                    /> :
                                                    item.pathType === 'circle' ?
                                                        <Ellipse
                                                            key={id}
                                                            cx={item.pageX}
                                                            cy={item.pageY}
                                                            rx={item.circleWidth}
                                                            ry={item.circleHeight}
                                                            stroke={color_list[item.color_id]}
                                                            strokeWidth={line_list[item.size_id].size}
                                                            fill="none"
                                                        /> :
                                                        <View key={id}>
                                                            <Path
                                                                d={item.arrowPath}
                                                                fill={color_list[item.color_id]}
                                                                stroke={color_list[item.color_id]}
                                                                strokeWidth={1}
                                                            />
                                                            <Path
                                                                key={id}
                                                                d={item.arrowSPath}
                                                                fill={color_list[item.color_id]}
                                                                stroke={color_list[item.color_id]}
                                                                strokeWidth={1}
                                                            />
                                                        </View>

                                        )
                                    })
                                }
                                {/**这是正在画着的线**/}
                                {
                                    drawType === 4 && isDrawing ?
                                        <Path
                                            d={this.state.drawPath}
                                            fill="none"
                                            strokeLinecap="round"
                                            stroke={this.state.currentColor}
                                            strokeWidth={this.state.currentSize}
                                        /> : null
                                }

                                {/**画笔🖌 结束**/}
                                {/***这是正在画的矩形***/}
                                {
                                    drawType === 5 && isDrawing ?
                                        <Rect
                                            x={this.state.rectFirstPageX}
                                            y={this.state.rectFirstPageY}
                                            rx="2"
                                            ry="2"
                                            width={this.state.rectWidth}
                                            height={this.state.rectHeight}
                                            fill="none"
                                            strokeWidth={this.state.currentSize}
                                            stroke={this.state.currentColor}
                                        /> : null
                                }
                                {/***这是正在画的椭圆***/}
                                {
                                    drawType === 3 && isDrawing ?
                                        <Ellipse
                                            cx={this.state.circleFirstPageX}
                                            cy={this.state.circleFirstPageY}
                                            rx={this.state.circleWidth}
                                            ry={this.state.circleHeight}
                                            stroke={this.state.currentColor}
                                            strokeWidth={this.state.currentSize}
                                            fill="none"
                                        /> : null
                                }
                                {/***这是箭头***/}
                                {
                                    drawType === 2 && isDrawing ?
                                        <>
                                            <Path
                                                d={this.state.arrowPath}
                                                fill={this.state.currentColor}
                                                stroke={this.state.currentColor}
                                                strokeWidth={1}
                                            />
                                            <Path
                                                d={this.state.arrowSPath}
                                                fill={this.state.currentColor}
                                                stroke={this.state.currentColor}
                                                strokeWidth={1}
                                            />
                                        </> : null
                                }
                            </Svg>
                        </View>
                    </ViewShot>
                    {
                        // <View
                        //     onLayout={this._onLayout.bind(this)}
                        //     style={[inputStyle,{backgroundColor: 'transparent', position: 'absolute', flex: 1,}]}>
                        //     <TextInput
                        //         placeholder={'请输入'}
                        //         placeholderTextColor='red'
                        //         multiline={false}
                        //         maxLength={11}
                        //         value={this.state.phone_mob}
                        //         autoFocus={true}
                        //         style={{fontSize: 13, width: '100%',color:'red'}}
                        //         onChangeText={(text) => this.setState({phone_mob: text})}
                        //         underlineColorAndroid={'transparent'}
                        //     />
                        // </View>
                    }
                    {isShowColorful ? this.renderColorful() : null}
                    {this.renderBottom()}
                </View>
            </View>
        );
    }


    renderBottom() {
        let {size_id, line_list, isShowLineSize, color_list, drawType} = this.state
        return (
            <View style={styles.camera_bottom}>
                <View style={[styles.bottom_item, {flex: 1}]}>
                    <Text style={styles.bottom_title}>选择</Text>
                    <View style={styles.bottom_icon}>
                        <View>
                            <Image source={require('../../images/opera/icon1.png')}
                                   style={{width: 15, height: 15}}/>
                        </View>
                        <TouchableOpacity onPress={() => this.onSelectDrawType(1)}>
                            <Image source={require('../../images/opera/icon2.png')}
                                   style={{width: 15, height: 15}}/>
                        </TouchableOpacity>
                    </View>
                </View>

                <View style={[styles.bottom_item, {flex: 2}]}>
                    <Text style={styles.bottom_title}>线条选择</Text>
                    <View style={styles.bottom_icon}>
                        <TouchableOpacity onPress={() => this.onSelectDrawType(2)}>
                            <Image
                                source={drawType === 2 ? require('../../images/opera/icon3_active.png') : require('../../images/opera/icon3.png')}
                                style={{width: 15, height: 15}}/>
                        </TouchableOpacity>
                        <TouchableOpacity onPress={() => this.onSelectDrawType(3)}>
                            <Image
                                source={drawType === 3 ? require('../../images/opera/icon4_active.png') : require('../../images/opera/icon4.png')}
                                style={{width: 15, height: 15}}/>
                        </TouchableOpacity>
                        <TouchableOpacity onPress={() => this.onSelectDrawType(4)}>
                            <Image
                                source={drawType === 4 ? require('../../images/opera/icon5_active.png') : require('../../images/opera/icon5.png')}
                                style={{width: 15, height: 15}}/>
                        </TouchableOpacity>
                        <TouchableOpacity onPress={() => this.onSelectDrawType(5)}>
                            <Image
                                source={drawType === 5 ? require('../../images/opera/icon6_active.png') : require('../../images/opera/icon6.png')}
                                style={{width: 15, height: 15}}/>
                        </TouchableOpacity>
                    </View>
                </View>

                <View style={[styles.bottom_item, {flex: 2}]}>
                    <View style={styles.bottom_icon}>
                        <Text style={styles.bottom_title}>粗细</Text>
                        <Text style={styles.bottom_title}>颜色</Text>
                    </View>
                    <View style={styles.bottom_icon}>
                        <TouchableOpacity onPress={() => this.onSelectDrawType(6)}
                                          style={{flexDirection: 'row', alignItems: 'center'}}>
                            <View style={{
                                height: line_list[size_id].size,
                                width: 60,
                                backgroundColor: '#333'
                            }}/>
                            <View>
                                <Image source={require('../../images/opera/triangle.png')}
                                       style={{width: 15, height: 15}}/>
                            </View>
                        </TouchableOpacity>

                        <TouchableOpacity style={styles.colorSelect} onPress={() => this.onSelectDrawType(7)}>
                            <View style={{
                                width: 16,
                                height: 16,
                                backgroundColor: color_list[this.state.color_id],
                                borderRadius: 2
                            }}/>
                            <Image source={require('../../images/opera/triangle.png')}
                                   style={{width: 15, height: 15}}/>
                        </TouchableOpacity>
                    </View>
                    {isShowLineSize ? this.renderLineSize() : null}
                </View>

                <View style={[styles.bottom_item, {flex: 2, borderRightWidth: 0}]}>
                    <Text style={styles.bottom_title}>操作</Text>
                    <View style={styles.bottom_icon}>
                        <TouchableOpacity onPress={() => this.revoke()} style={styles.bottom_btn}>
                            <Text style={{fontSize: 12}}>撤销</Text>
                        </TouchableOpacity>
                        <TouchableOpacity onPress={() => this.clearOut()} style={styles.bottom_btn}>
                            <Text style={{fontSize: 12}}>清空</Text>
                        </TouchableOpacity>
                        <TouchableOpacity onPress={() => this.savePhoto()}
                                          style={[styles.bottom_btn, {backgroundColor: '#203990'}]}>
                            <Text style={{fontSize: 12, color: '#fff'}}>保存</Text>
                        </TouchableOpacity>
                    </View>
                </View>
            </View>
        )
    }

    //线条
    renderLineSize() {
        let {line_list} = this.state
        return (
            <View style={styles.lineSelect}>
                {
                    line_list.map((item, id) => {
                        return (
                            <TouchableOpacity onPress={() => this.onSelectLineSize(item, id)}
                                              key={id} style={{flex: 1, justifyContent: 'center'}}>
                                <View style={{
                                    height: item.size,
                                    width: 60,
                                    backgroundColor: '#333'
                                }}/>
                            </TouchableOpacity>
                        )
                    })
                }
            </View>
        )
    }

    //颜色
    renderColorful() {
        let {color_list} = this.state
        return (
            <View style={styles.kindsOfColors}>
                {
                    color_list.map((item, id) => {
                        return (
                            <TouchableOpacity onPress={() => this.onSelectColor(item, id)}
                                              key={id} style={[styles.ColorItem, {backgroundColor: item}]}>
                            </TouchableOpacity>
                        )
                    })
                }
            </View>
        )
    }

}

export default Comp3;
const styles = StyleSheet.create({
    /**内容*/
    container: {
        flex: 1,
    },
    camera_bottom: {
        backgroundColor: '#fff',
        height: '25%',
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'center'
    },

    bottom_item: {
        paddingHorizontal: 10,
        borderRightWidth: 1,
        borderColor: '#eee',
        height: '70%',
        justifyContent: 'space-between'
    },
    bottom_icon: {
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'space-between',
    },
    bottom_title: {fontSize: 12, marginBottom: 10},
    bottom_btn: {
        borderWidth: 1,
        borderRadius: 999,
        width: '30%',
        borderColor: '#A5AAC1',
        justifyContent: 'center',
        alignItems: 'center',
        paddingVertical: 3
    },
    colorSelect: {
        flexDirection: 'row',
        alignItems: 'center',
        borderWidth: 1,
        borderRadius: 5,
        paddingHorizontal: 2,
        paddingVertical: 2,
        borderColor: '#eee'
    },
    lineSelect: {
        backgroundColor: 'red',
        position: 'absolute',
        // bottom:0,
        height: '100%',
        width: 85,
    },
    kindsOfColors: {
        width: '100%',
        backgroundColor: '#fff',
        height: '50%',
        flexDirection: 'row',
        alignItems: 'center',
        flexWrap: 'wrap',
        justifyContent: 'space-around',
        paddingVertical: 10
    },
    ColorItem: {
        height: '50%',
        width: 60,
        borderWidth: 1,
        marginBottom: 5,
        borderColor: '#eee'
    },


});

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容