react-native 畫筆(寫字板、手寫板)--1

參考鏈接:http://www.reibang.com/p/504c639063b3
前提:集成好react-native-svg

以上鏈接博主大佬用的是ART繪畫系統(tǒng)顺少,受此啟發(fā)我就使用SVG畫圖了,因為項目里面還有其他操作淫痰,例如箭頭把介、圓圈、矩形等類似電腦截圖后編輯操作厢漩,而ART用法個人不是很熟悉膜眠,所以采用SVG,SVG不是很熟悉的可以看一下我之前寫的這篇http://www.reibang.com/p/ef91237a89a4,也可以自己上菜鳥教程簡單的練一下再上手宵膨,做了個小demo架谎,效果圖如下:

441637732888_.pic.jpg

把以下代碼復制粘貼到一個新頁面即可嘗試,至于Util.size.width辟躏、Util.size.height是屏幕寬高谷扣,換一下就好了。這只是畫線功能捎琐,其他功能效果(例如圓圈会涎、矩形、箭頭等功能)請看另外一篇文章: http://www.reibang.com/p/06d3bdfae98a

import React, {Component} from 'react';
import {View, Text, StyleSheet, Image, TouchableOpacity, PanResponder, ART, ImageBackground} from 'react-native'
import Util from './common/util'
import Svg, {Path} from "react-native-svg";

class SvgDrawTest extends Component {
    constructor(props) {
        super(props);
        this.allPoint = ''
        this.state = {
            // drawPath: 'M25 10 L98 65 L70 25 L16 77 L11 30 L0 4 L90 50 L50 10 L11 22 L77 95 L20 25'
            drawPath: ''
        }
    }

    componentWillMount() {
        this._panResponderDrawLine = PanResponder.create({
            onStartShouldSetPanResponder: (evt, gestureState) => true,
            onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
            onMoveShouldSetPanResponder: (evt, gestureState) => true,
            onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,

            onPanResponderGrant: (evt, gestureState) => {
                let tempfirstX = evt.nativeEvent.pageX
                let tempFirstY = evt.nativeEvent.pageY
                this.firstPoint = ' M' + tempfirstX + ' ' + tempFirstY
                this.allPoint = this.allPoint + this.firstPoint   //上一次的畫的全部的點(this.allPoint)瑞凑,拼接上當前這次畫的M點末秃,在svg中M為線的起始點,拼接上后在 onPanResponderMove 中將當前移動的所有點再次拼接,當前和之前的拼接完之后,更新頁面線條
            },

            onPanResponderMove: (evt, gestureState) => {
                let pointX = evt.nativeEvent.pageX
                let pointY = evt.nativeEvent.pageY
                // console.log(`X:${pointX}`, `Y:${pointY}`)
                let point = ' L' + pointX + ' ' + pointY
                this.allPoint += point
                console.log('point====', this.allPoint)
                let drawPath = this.allPoint
                this.setState({
                    drawPath
                })
            },

            onPanResponderTerminationRequest: (evt, gestureState) => true,
            onPanResponderRelease: (evt, gestureState) => { },

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

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

    }

    clearOut(){
        this.allPoint = ''
        this.setState({
            drawPath:''
        })
    }

    render() {
        return (
            <View>
                <View style={{width:Util.size.width,height:Util.size.height-60, backgroundColor: 'green'}}
                      {...this._panResponderDrawLine.panHandlers}
                >
                    <Svg height="100%" width="100%">
                        <Path
                            d={this.state.drawPath}
                            fill="none"
                            stroke="red"
                            strokeWidth="5"
                        />
                    </Svg>
                </View>
                <TouchableOpacity onPress={()=>this.clearOut()} style={styles.btn}>
                    <Text style={{color:'#333',fontSize:16}}>清空</Text>
                </TouchableOpacity>
            </View>

    );
    }
}

export default SvgDrawTest;
const styles = StyleSheet.create({
    btn:{elevation:5,backgroundColor:'#fff',paddingHorizontal:30,paddingVertical:10,borderRadius:999,justifyContent:'center',alignItems:'center'},
})

在項目里使用實例籽御,效果圖如下


192451637727165_.pic.jpg

本來在手勢那里蛔溃,因為畫圖是在圖片范圍內,我是嘗試用locationX,locationY 而不是pageX篱蝇、pageY,后來發(fā)現(xiàn)
locationX超過范圍后那個點會返回對立的那一面贺待,想著解決太麻煩了,所以采用pageX和pageY,如圖所見零截,手勢起始點的位置和移動的位置點減去他的邊距即可麸塞。目前是畫筆,后續(xù)操作實現(xiàn)了再更新實現(xiàn)代碼涧衙。

import React, {Component} from 'react';
import {View, Text, Image, StyleSheet, PanResponder,TouchableOpacity} from 'react-native'
import Svg, {Path} from "react-native-svg";

let marginY = 50 + 15 + 5  //頭部導航height 50  下方內容padding 15  圖片與父盒子距離 5
let marginX = 15 + 5  //  下方內容padding 15  圖片與父盒子距離 5

class Comp3 extends Component {
    constructor(props) {
        super(props);
        this.allPoint = ''
        this.state = {
            drawPath: ''
        }
    }

    componentWillMount() {

        this._panResponderDrawLine = PanResponder.create({
            onStartShouldSetPanResponder: (evt, gestureState) => true,
            onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
            onMoveShouldSetPanResponder: (evt, gestureState) => true,
            onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,

            onPanResponderGrant: (evt, gestureState) => {
                let tempfirstX = evt.nativeEvent.pageX.toFixed(0)-marginX
                let tempFirstY = evt.nativeEvent.pageY.toFixed(0)-marginY
                this.firstPoint = ' M' + tempfirstX + ' ' + tempFirstY
                this.allPoint += this.firstPoint   //上一次的畫的全部的點(this.allPoint)哪工,拼接上當前這次畫的M點,在svg中M為線的起始點,拼接上后在 onPanResponderMove 中將當前移動的所有點再次拼接,當前和之前的拼接完之后弧哎,更新頁面線條
            },

            onPanResponderMove: (evt, gestureState) => {
                let pointX = evt.nativeEvent.pageX.toFixed(0)-marginX
                let pointY = evt.nativeEvent.pageY.toFixed(0)-marginY
                // console.log(`X:${pointX}`, `Y:${pointY}`)
                let point = ` L${pointX} ${pointY}`
                this.allPoint += point
                let drawPath = this.allPoint
                this.setState({
                    drawPath
                })
            },

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


    render() {
        return (
            <View style={styles.content_left}>
                <View style={{flex: 1}} {...this._panResponderDrawLine.panHandlers}>
                    <Image
                        source={require('../images/default.jpg')}
                        style={{height: '100%', width: '100%', position: 'absolute'}}
                    />
                    <Svg height="100%" width="100%">
                        <Path
                            d={this.state.drawPath}
                            fill="none"
                            stroke="red"
                        />
                    </Svg>
                </View>

                <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>
                            <View>
                                <Image source={require('../images/opera/icon2.png')}
                                       style={{width: 15, height: 15}}/>
                            </View>
                        </View>
                    </View>

                    <View style={[styles.bottom_item, {flex: 2}]}>
                        <Text style={styles.bottom_title}>線條選擇</Text>
                        <View style={styles.bottom_icon}>
                            <View>
                                <Image source={require('../images/opera/icon3.png')}
                                       style={{width: 15, height: 15}}/>
                            </View>
                            <View>
                                <Image source={require('../images/opera/icon4.png')}
                                       style={{width: 15, height: 15}}/>
                            </View>
                            <View>
                                <Image source={require('../images/opera/icon5.png')}
                                       style={{width: 15, height: 15}}/>
                            </View>
                            <View>
                                <Image source={require('../images/opera/icon6.png')}
                                       style={{width: 15, height: 15}}/>
                            </View>
                        </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}>
                            <View style={{flexDirection: 'row', alignItems: 'center'}}>
                                <Image source={require('../images/opera/icon7.png')}
                                       style={{width: 60, height: 3}}/>
                                <View>
                                    <Image source={require('../images/opera/triangle.png')}
                                           style={{width: 15, height: 15}}/>
                                </View>
                            </View>

                            <View style={styles.colorSelect}>
                                <View style={{width: 16, height: 16, backgroundColor: 'red', borderRadius: 2}}/>
                                <Image source={require('../images/opera/triangle.png')}
                                       style={{width: 15, height: 15}}/>
                            </View>
                        </View>
                    </View>

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

                </View>
            </View>
        );
    }
}

export default Comp3;
const styles = StyleSheet.create({
    /**內容*/
    content_left: {
        backgroundColor: '#fff',
        flex: 3,
        marginRight: 15,
        padding: 5,
    },
    content_left_camera: {
        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'
    },


});

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末雁比,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子撤嫩,更是在濱河造成了極大的恐慌偎捎,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件序攘,死亡現(xiàn)場離奇詭異茴她,居然都是意外死亡,警方通過查閱死者的電腦和手機程奠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門丈牢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人瞄沙,你說我怎么就攤上這事己沛』藕耍” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵申尼,是天一觀的道長遂铡。 經(jīng)常有香客問我,道長晶姊,這世上最難降的妖魔是什么扒接? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮们衙,結果婚禮上钾怔,老公的妹妹穿的比我還像新娘。我一直安慰自己蒙挑,他們只是感情好宗侦,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著忆蚀,像睡著了一般矾利。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上馋袜,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天男旗,我揣著相機與錄音,去河邊找鬼欣鳖。 笑死察皇,一個胖子當著我的面吹牛,可吹牛的內容都是我干的泽台。 我是一名探鬼主播什荣,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼怀酷!你這毒婦竟也來了稻爬?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤蜕依,失蹤者是張志新(化名)和其女友劉穎桅锄,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體笔横,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡竞滓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了吹缔。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡锯茄,死狀恐怖厢塘,靈堂內的尸體忽然破棺而出茶没,到底是詐尸還是另有隱情,我是刑警寧澤晚碾,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布抓半,位于F島的核電站,受9級特大地震影響格嘁,放射性物質發(fā)生泄漏笛求。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一糕簿、第九天 我趴在偏房一處隱蔽的房頂上張望探入。 院中可真熱鬧,春花似錦懂诗、人聲如沸蜂嗽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽植旧。三九已至,卻和暖如春离唐,著一層夾襖步出監(jiān)牢的瞬間病附,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工亥鬓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留胖喳,地道東北人。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓贮竟,卻偏偏與公主長得像丽焊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子咕别,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內容