亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Swift3.0學習實踐-一個簡單的畫板(七色軌跡、可撤銷、可清除、帶橡皮擦)

2019-11-09 15:51:00
字體:
來源:轉載
供稿:網友

寫著玩兒的小程序,繼續學習swift.運行效果+代碼+知識點總結

運行效果:

           

代碼:

Canvas類:畫布,畫圖板狀態管理、交互、處理手勢
class Canvas:UIView{    //負責線條的生成、操作與管理    let pathCreator:PathCreator    //是否處于擦除狀態    var isInErasering:Bool    //橡皮擦視圖    let eraserView:UIView        override init(frame: CGRect) {        isInErasering = false        pathCreator = PathCreator()                eraserView = UIView.init()        eraserView.frame = CGRect(x: 0, y: 0, width: 10, height: 10)        eraserView.backgroundColor = UIColor.white        eraserView.alpha = 0        super.init(frame: frame)                self.backgroundColor = UIColor.black                self.addSubview(eraserView)                let revokeBut = UIButton(type: UIButtonType.system)        revokeBut.frame = CGRect(x: 20, y: 20, width: 80, height: 30)        revokeBut.setTitle("撤銷", for: UIControlState.normal)        revokeBut.addTarget(self, action: #selector(revokeButClick), for: UIControlEvents.touchUpInside)        self.addSubview(revokeBut)                let cleanBut = UIButton(type: UIButtonType.system)        cleanBut.frame = CGRect(x: 110, y: 20, width: 80, height: 30)        cleanBut.setTitle("清空", for: UIControlState.normal)        cleanBut.addTarget(self, action: #selector(cleanButClick), for: UIControlEvents.touchUpInside)        self.addSubview(cleanBut)            let eraserBut = UIButton(type: UIButtonType.system)        eraserBut.frame = CGRect(x: 200, y: 20, width:80, height: 30)        eraserBut.setTitle("橡皮", for: UIControlState.normal)        eraserBut.setTitle("畫筆", for: UIControlState.selected)        eraserBut.addTarget(self, action: #selector(eraserButClick(but:)), for: UIControlEvents.touchUpInside)        self.addSubview(eraserBut)                let ges = UipanGestureRecognizer(target: self, action:#selector(handleGes(ges:)))        ges.maximumNumberOfTouches = 1        self.addGestureRecognizer(ges)    }        required public init?(coder aDecoder: NSCoder) {        fatalError("init(coder:) has not been implemented")    }        override public func layoutSubviews() {            }        @objc PRivate func handleGes(ges:UIPanGestureRecognizer) -> Void {        let point = ges.location(in: self)        switch ges.state {        case UIGestureRecognizerState.began:            if isInErasering {                //擦除狀態,顯示出橡皮擦                eraserView.alpha = 1                eraserView.center = point            }            //生成新的一筆            pathCreator.addNewPath(to: point,isEraser: isInErasering)            self.setNeedsDisplay()        case UIGestureRecognizerState.changed:            if isInErasering {                //移動橡皮擦                eraserView.center = ges.location(in: self)            }            //更新當前筆畫路徑            pathCreator.addLineForCurrentPath(to: point,isEraser:isInErasering)            self.setNeedsDisplay()        case UIGestureRecognizerState.ended:            if isInErasering {                //擦除狀態,隱藏橡皮擦                eraserView.alpha = 0                eraserView.center = ges.location(in: self)            }            //更新當前筆畫路徑            pathCreator.addLineForCurrentPath(to: point,isEraser: isInErasering)            self.setNeedsDisplay()        case UIGestureRecognizerState.cancelled:            print("cancel")        case UIGestureRecognizerState.failed:            print("fail")        default:            return        }    }        override public func draw(_ rect: CGRect) {        //畫線        pathCreator.drawPaths()    }        @objc private func revokeButClick()->Void{        //撤銷操作        pathCreator.revoke()        self.setNeedsDisplay()    }        @objc private func cleanButClick()->Void{        //清空操作        pathCreator.clean()        self.setNeedsDisplay()    }        @objc private func eraserButClick(but:UIButton)->Void{        //切換畫圖與擦除狀態        if but.isSelected {            but.isSelected = false            isInErasering = false        }else{            but.isSelected = true            isInErasering = true        }    }}

PathCreator:具體線條繪制、管理

//每條子線段信息struct BezierInfo{    let path:UIBezierPath//具體線段    let color:UIColor//線段對應顏色    init(path:UIBezierPath,color:UIColor){        self.path = path        self.color = color    }}class PathCreator{    //所有筆畫    private var paths:[NSMutableArray]?    //筆畫內當前子線段    private var currentBezierPathInfo:BezierInfo?    //當前筆畫的所有子線段    private var currentPath:NSMutableArray?    //當前筆畫已經采集處理了幾個觸摸點    private var pointCountInOnePath = 0        static let colors = [UIColor.red,UIColor.orange,UIColor.yellow,UIColor.green,UIColor.blue,UIColor.gray,UIColor.purple]    init() {        paths = []    }    //添加新筆畫    func addNewPath(to:CGPoint,isEraser:Bool)->Void{        //創建起始線段        let path = UIBezierPath()        path.lineWidth = 5        path.move(to: to)        path.lineJoinStyle = CGLineJoin.round        path.lineCapStyle = CGLineCap.round        if !isEraser {            //綁定線段與顏色信息            currentBezierPathInfo = BezierInfo(path: path, color: PathCreator.colors[0])        }else{            //處于擦除模式,顏色與畫板背景色相同            currentBezierPathInfo = BezierInfo(path: path, color: UIColor.black)        }        //新建一個筆畫        currentPath = NSMutableArray.init()        //將起始線段加入當前筆畫        currentPath!.add(currentBezierPathInfo)        pointCountInOnePath = 0        //將當前筆畫加入筆畫數組        paths!.append(currentPath!)    }    //添加新的點,更新當前筆畫路徑    func addLineForCurrentPath(to:CGPoint,isEraser:Bool) -> Void {        pointCountInOnePath += 1//同一筆畫內,每7個點換一次顏色        if pointCountInOnePath % 7 == 0{//換顏色            if let currentBezierPathInfo = currentBezierPathInfo{                //將當前點加入當前子線段,更新當前子線段路徑                currentBezierPathInfo.path.addLine(to: to)            }            //生成新的子線段            let path = UIBezierPath()            path.lineWidth = 5            path.move(to: to)            path.lineJoinStyle = CGLineJoin.round            path.lineCapStyle = CGLineCap.round            if !isEraser{                //給當前子線段設置下一個顏色                currentBezierPathInfo = BezierInfo(path: path, color: PathCreator.colors[currentPath!.count % 7])            }else{                //處于擦除模式,顏色與畫板背景色相同                currentBezierPathInfo = BezierInfo(path: path, color: UIColor.black)            }            //將當前子線段加入當前筆畫            currentPath!.add(currentBezierPathInfo)        }else{            if let currentBezierPathInfo = currentBezierPathInfo{                //將當前點加入當前子線段,更新當前子線段路徑                currentBezierPathInfo.path.addLine(to: to)            }        }    }        func drawPaths()->Void{        //畫線        let pathCount = paths!.count        for i in 0..<pathCount{            //取出所有筆畫            let onePath = paths![i]            let onePathCount = onePath.count            for j in 0..<onePathCount{                //繪制每條筆畫內每個子線段                let pathInfo = onePath.object(at: j) as! BezierInfo                pathInfo.color.set()                pathInfo.path.stroke()            }        }    }        func revoke()->Void{        //移走上一筆畫        if paths!.count > 0 {            paths!.removeLast()        }    }        func clean()->Void{        //移走所有筆畫        paths!.removeAll()    }}

知識點總結:

1.結構體是值傳遞

一個基礎概念,但開始使用時還是給忘了。數組[]在swift中是結構體(struct)實現,值傳遞。最開始把currentPath聲明為了[],添加到paths[]中后,后續再去往currentPath中添加元素,paths中的對應的currentpath對象內容并未隨之發生改變,后將currentPath改為了NSMutableArray(引用傳遞).

2.selector、@objc、private

(純)swift與oc采用了不同的運行機制,swift不再采用與oc一樣的運行時(runtime)與消息分發機制,selector作為oc運行機制的產物,swift中也對其進行了保留與支持。

@objc修飾符的作用是將swift定義的類、方法等暴露給oc。

于是,下列selector中指定的方法,都要使用@objc進行修飾

cleanBut.addTarget(self, action: #selector(cleanButClick), for: UIControlEvents.touchUpInside)
let ges = UIPanGestureRecognizer(target: self, action:#selector(handleGes(ges:)))如果一個swift類繼承自NSObject,swift會默認給該類的非private屬性或方法加上@objc修飾。因為Canvas類(->UIView->UIResponder->NSObject)繼承自NSObject,所以其屬性或方法(非private)都會被自動加上@objc修飾但是因為我代碼中的這幾個selector指向的方法都聲明為了private,所以還是需要手動去做@objc修飾(如果是非private的,可以不寫@objc)
@objc private func handleGes(ges:UIPanGestureRecognizer) -> Void

3.required的構造函數

required用于修飾構造方法,用于要求子類必需實現對應的構造方法如果子類中沒有實現任何構造方法,則不必去顯式的實現父類要求的required構造方法;而當子類中有定義實現構造方法時,則必需顯式的去實現父類要求的required構造方法,同時還要保留required修飾.當實現一個類Canvas繼承自UIView時,我們可以看到編譯器強制要求我們實現構造方法
public init?(coder aDecoder: NSCoder)通過xcode找到該方法是在NSCoding協議中被定義的
public protocol NSCoding {    public func encode(with aCoder: NSCoder)    public init?(coder aDecoder: NSCoder) // NS_DESIGNATED_INITIALIZER}可以看到,此處并沒有進行requird修飾,為什么還要求強制實現該構造方法呢?因為在協議中規定的構造方法,不用顯式進行requird修飾,實現協議的對應類默認必需要去實現協議中規定的構造方法,且加上requird修飾

4.as

let x:UInt16 = 100let y:UInt8 = 10//x + y會報錯,不自動類型轉換,更安全let n = UInt8(x) + y上面例子中,當我們進行值類型之間的類型轉換(UInt16->UInt8)時,其實借助的是UInt8的構造方法
/// Create an instance initialized to `value`.    public init(integerLiteral value: UInt8)而當引用類型之間需要進行強制轉換時,則需要借助as操作符因為轉換可能失敗(兩個不相關的類之間進行轉換),所以需要使用as?,轉換結果為一個可選型,不成功時,可選型值為nil當然,如果可以肯定轉換是成功的,則可以使用as!進行轉換,結果為目標類型的對象。另外,看下面這個例子
var people:People?let man:Man = Man()people = manprint(people)//可選型變量let beMan = people as! Manprint (beMan)//強制轉化后beMan不是可選型
var people:People?let man:Man = Man()people = manprint(people)//可選型變量let beMan = people as! Man?print (beMan)//強制轉化后beMan為可選型轉換后的結果類型完全由as!后面的目標類型決定,即便原對象在轉換之前是可選型對象,但如果轉換的目標類型不是可選型,則轉換后得到的也就不是一個可選型了
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
在线电影欧美日韩一区二区私密| 亚洲自拍欧美另类| 国产成人精品一区二区| 7777精品久久久久久| 日韩av中文字幕在线免费观看| 国产精品大陆在线观看| 国产精品久久久久久亚洲影视| 欧美精品在线播放| 日韩三级影视基地| 欧美在线观看日本一区| 亚洲午夜色婷婷在线| 国产午夜精品麻豆| 国产精品久久久久久久久久新婚| 丰满岳妇乱一区二区三区| 精品夜色国产国偷在线| 久久中文字幕一区| 欧美一级bbbbb性bbbb喷潮片| 亚洲国产精品视频在线观看| 欧美成人精品不卡视频在线观看| 成人情趣片在线观看免费| 人人做人人澡人人爽欧美| 国产日韩欧美在线观看| 国产成一区二区| 成人妇女淫片aaaa视频| 日韩在线视频观看| 亚洲毛片在线观看.| 日韩精品高清视频| 精品自拍视频在线观看| 国产精品久久久久91| 久久精品美女视频网站| 一区二区日韩精品| 国产日韩欧美一二三区| 亚洲成人黄色在线观看| 91精品视频在线| 欧美男插女视频| 欧美在线欧美在线| 性色av一区二区三区| 热99久久精品| 欧美成人午夜免费视在线看片| 成人久久一区二区| 精品视频www| 欧美一级电影免费在线观看| 日韩h在线观看| 精品女同一区二区三区在线播放| 97热在线精品视频在线观看| 日韩久久精品电影| 久久久久久久一区二区三区| 欧美性猛交xxxx乱大交| 欧美高跟鞋交xxxxxhd| 亚洲最大成人免费视频| 免费91麻豆精品国产自产在线观看| 7777精品久久久久久| 日韩精品视频免费在线观看| 91精品91久久久久久| 成人国产精品av| 欧美激情在线狂野欧美精品| 在线观看免费高清视频97| 中文字幕日本精品| 国产精品美女免费| 久久精品这里热有精品| 欧美国产视频日韩| 亚洲成人av片在线观看| 亚洲欧美日韩一区二区在线| 日本国产欧美一区二区三区| 国产精品va在线| 亚洲四色影视在线观看| 欧美成人精品一区| 深夜福利91大全| 91po在线观看91精品国产性色| 日韩激情av在线免费观看| 日韩高清人体午夜| 久久中文字幕在线| 国产亚洲精品久久久久久| 日韩中文字幕欧美| 伊人精品在线观看| 国产网站欧美日韩免费精品在线观看| 国产精品999999| 九九久久久久久久久激情| 久久久亚洲影院你懂的| 91最新在线免费观看| 亚洲天堂网站在线观看视频| 欧美最猛性xxxxx(亚洲精品)| 国产精品久久久久久久久久新婚| 亚洲国产精品久久久| 欧美精品videos性欧美| 91精品在线观看视频| 激情久久av一区av二区av三区| 国产91露脸中文字幕在线| 97国产在线视频| www.xxxx精品| 久久九九免费视频| 亚洲国产91色在线| 日本成人精品在线| 亚洲电影成人av99爱色| 欧美另类第一页| 日本精品免费观看| 欧美另类在线观看| 国产精品天天狠天天看| 国内精品久久久久影院优| 欧美视频不卡中文| 国产精选久久久久久| 96国产粉嫩美女| 日韩有码在线电影| 最近免费中文字幕视频2019| 久久国产精品99国产精| 欧美高清视频在线| 懂色av影视一区二区三区| 日韩激情在线视频| 国产69精品久久久久9| www亚洲欧美| 亚洲影院色无极综合| 色噜噜亚洲精品中文字幕| 日韩欧美国产高清91| 欧美午夜精品久久久久久人妖| 亚洲国产天堂久久国产91| 成人黄色中文字幕| 日韩资源在线观看| 亚洲精品mp4| 日韩高清电影好看的电视剧电影| 久久久国产精彩视频美女艺术照福利| 久久久久久999| 成人黄色生活片| 亚洲一区二区三区久久| 久久久伊人欧美| 97av视频在线| 亚洲精品在线不卡| 国产精品99久久99久久久二8| 亚洲精品久久久久国产| 国产精品爽爽爽爽爽爽在线观看| 国产精品综合不卡av| 久久久97精品| 欧美性猛交xxxx乱大交| 日日狠狠久久偷偷四色综合免费| 亚洲新中文字幕| 久久国产精品网站| 国产成人av网址| 成人在线观看视频网站| 久久精品免费电影| 国产日韩欧美在线播放| 两个人的视频www国产精品| 国产精品免费看久久久香蕉| 国产亚洲免费的视频看| 亚洲国产欧美久久| 色妞色视频一区二区三区四区| 日韩电影中文 亚洲精品乱码| 欧美在线视频观看免费网站| 国产精品日韩在线一区| 日韩毛片在线观看| 欧美精品久久久久久久免费观看| 中文字幕亚洲天堂| 欧美激情影音先锋| 亚洲欧美日韩区| 亚洲精品国产综合久久| 亚洲在线观看视频| 亚洲一品av免费观看| 午夜伦理精品一区| 国产日韩欧美中文在线播放| 欧美亚洲国产成人精品| 国产成人免费91av在线| 精品国产31久久久久久| 日韩精品一二三四区| 91色视频在线观看| 亚洲男人天堂2024| 亚洲视频日韩精品|