8.22 Draw 画图板

面向接口编程,多个类的共同点提出来,当做接口,充分利用多态的特性减少判断,利用封装,继承,能使得代码更加清晰易读,添加功能也不需要改太多东西。可扩展性高

将需要画的线,矩形,椭圆等都写成类

import UIKit

class ViewController: UIViewController {
    
    @IBAction func didClicked(sender: UIButton) {
        let cv = self.view as! CustomView
//        let array = cv.array
        
        let path = NSHomeDirectory() + "/Documents/1.jpg"
        //
        //        NSKeyedArchiver.archiveRootObject(array, toFile: path)
        
        //1. 开始一个image上下文,绘制在内存的一个区域,保存为JPG
        UIGraphicsBeginImageContext(self.view.bounds.size)
        //2. 获取image context
        
        //a.
        //        let context = UIGraphicsGetCurrentContext()
        //
        //        for line in array {
        //            line.draw(context!)
        //        }
        //
        //        CGContextDrawPath(context, .Stroke)
        
        //b. 将视图上的所有内容绘制到当前的context中
        //截屏
        cv.drawViewHierarchyInRect(cv.bounds, afterScreenUpdates: true)
        
        //3. 从当前上下文中获取图片(UIImage)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        //        let data = UIImagePNGRepresentation(image) //UIImage -> NSData
        let data = UIImageJPEGRepresentation(image, 0.4)
        try! data?.writeToFile(path, options: .AtomicWrite)
        
        //4. 结束图形上下文
        UIGraphicsEndImageContext()
        
        
        
        //1. 可以自动转换
        //Int/Float... <-> NSNumber
        //String <-> NSString
        //2. 容器的转换有条件,元素必须能够自动转换
        //Dictionary <-> NSDictionary
        //Array <-> NSArray
        //        var strArray = Array<String>()
        //        for point in array {
        //            //CGPoint -> NSString
        //            strArray.append(NSStringFromCGPoint(point))
        //        }
        //        //NSArray是一个不可变类型
        //        (strArray as NSArray).writeToFile(path, atomically: true)
    }
    
    func changeShape(type: Shape.Type) {
        let cv = self.view as! CustomView
        cv.type = type
    }
    
    //meta programming
    //meta type: 元类型
    @IBAction func didLineClicked(sender: UIButton) {
        changeShape(Line.self)
    }
    
    @IBAction func didRectClicked(sender: UIButton) {
        changeShape(Rectangle.self)
    }
    
    @IBAction func didCurveClicked(sender: UIButton) {
        changeShape(Curve.self)
    }
    
    @IBAction func didCircleClicked(sender: AnyObject) {
        changeShape(Circle.self)
    }
    @IBAction func RedColor(sender: UIButton) {
        let cv = self.view as! CustomView
        cv.color = UIColor.redColor().self
    }
    
    @IBAction func BlueColor(sender: UIButton) {
        let cv = self.view as! CustomView
        cv.color = UIColor.blueColor().self

    }
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let cv = self.view as! CustomView
        
        let path = NSHomeDirectory() + "/Documents/array.plist"
        let array = NSKeyedUnarchiver.unarchiveObjectWithFile(path)
        
        if let a = array as? Array<Line> {
            
            cv.array = a
        }
        
        //        let strArray = NSArray(contentsOfFile: path)!
        //        for str in strArray {
        //            //NSString -> CGPoint
        //            let point = CGPointFromString(str as! String)
        //            cv.array.append(point)
        //        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

import UIKit

class CustomView: UIView {
    var array = Array<Shape>()
    var type: Shape.Type = Line.self //默认为Line类型
    var color: UIColor?
    // Only override drawRect: if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    //1. 视图显示
    //2. 大小、位置改变
    override func drawRect(rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        
        for shape in array {
            
            CGContextSetLineWidth(context, 3)
            CGContextSaveGState(context)
            
            CGContextSetStrokeColorWithColor(context,shape.color?.CGColor)
            //多态
            shape.draw(context!)
            
            CGContextStrokePath(context)
        }
        
        CGContextDrawPath(context, .Stroke)
    }
    
    func pointForTouches(touches: Set<UITouch>) -> CGPoint {
        
        let touch = touches.first! //UITouch
        let point = touch.locationInView(self)
        
        return point
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        //获取起点
        let point = pointForTouches(touches)
        
        let shape = type.init() //必须有required的构造函数
        if color != nil {
            shape.color = color!
        }
        shape.addPoint(point)
        array.append(shape)
    }
    
    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
        //获取动态点
        let point = pointForTouches(touches)
        
        let shape = array.last
        shape?.addPoint(point)
        
        self.setNeedsDisplay() //强制刷新(重绘)
    }
    
    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        //获取终点
        let point = pointForTouches(touches)
        
        let shape = array.last
        shape?.addPoint(point)
        
        self.setNeedsDisplay() //强制刷新(重绘)
    }
}

import UIKit

//enum ShapeType {
//    case Line
//    case Rect
//    case Ellipse
//}

//定义接口协议,方便其他类调用
protocol ShapeProtocol {
    func draw(context: CGContextRef)
    func addPoint(point: CGPoint)
}

class Shape: NSObject, NSCoding, ShapeProtocol {
    
//    var begin: CGPoint!
//    var end: CGPoint!
//    var cgcolor: CGColor!
    
    
    //NSArray中只能存放对象
    var points = Array<Point>()
    var color:UIColor!
    required override init() {
        super.init()
        
    }
    
    required init?(coder aDecoder: NSCoder) {
//        begin = aDecoder.decodeCGPointForKey("begin")
//        end = aDecoder.decodeCGPointForKey("end")
        
//        取数据
        if let array = aDecoder.decodeObjectForKey("points") as? Array<Point> {
            points = array
        }
        if let m = aDecoder.decodeObjectForKey("color") as?  UIColor{
            color = m
        }
    }
//    存数据
    func encodeWithCoder(aCoder: NSCoder) {
//        aCoder.encodeCGPoint(begin, forKey: "begin")
//        aCoder.encodeCGPoint(end, forKey: "end")
        
        aCoder.encodeObject(points, forKey: "points")
        aCoder.encodeObject(color, forKey: "color")

    }
    
    func draw(context: CGContextRef) {
    }
    
    func addPoint(point: CGPoint) {  
    }
}

import UIKit
//两个点之间的画图,如线,矩形,定义为SimpleShape简单图形类,继承Shape图形类
class SimpleShape: Shape {
    override func addPoint(point: CGPoint) {
        let p = Point(point: point)
        
        if points.count < 2 {
            points.append(p)
        }
        else {
            points[1] = p
        }
    }
}

import UIKit
//线
class Line: SimpleShape  {
 
    override func draw(context: CGContextRef) {
//        安全检查,如果少于两个点,就不画了
        if points.count < 2 {
            return
        }
        
        CGContextMoveToPoint(context, points[0].x, points[0].y)
        CGContextAddLineToPoint(context, points[1].x, points[1].y)
    }
}

import UIKit
//矩形
class Rectangle: SimpleShape {
    override func draw(context: CGContextRef) {
//        安全检查,必须大于等于两个点才画
        guard points.count >= 2 else {
            return
        }
        
        CGContextAddRect(context, CGRect(x: points[0].x, y: points[0].y, width: points[1].x - points[0].x, height: points[1].y - points[0].y))
    }
}

---------------------------

```bash
import UIKit
任意线
class Curve: Shape {
    override func addPoint(point: CGPoint) {
        let p = Point(point: point)
        
        points.append(p)
    }
    
    override func draw(context: CGContextRef) {
        if points.count < 2 {
            return
        }
        
        CGContextMoveToPoint(context, points[0].x, points[0].y)
        for p in points {
            CGContextAddLineToPoint(context, p.x, p.y)
        }
    }
}

import UIKit
//椭圆
class Circle: SimpleShape {
    override func draw(context: CGContextRef) {
        let begin = points[0] //圆心
        let end = points[1]
        
//        求半径
        //r = ((x1-x0)**2 + (y1-y0)**2)^2
        let radius = sqrt(pow((end.x - begin.x), 2) + pow((end.y - begin.y), 2))
        
        CGContextAddEllipseInRect(context, CGRect(x: begin.x - radius, y: begin.y - radius, width: radius + radius, height: radius + radius))
    }
}

import UIKit

class Point: NSObject, NSCoding {
    var x: CGFloat = 0
    var y: CGFloat = 0
    
    init(point: CGPoint) {
        super.init()
        
        x = point.x
        y = point.y
    }
//    取数据
    required init?(coder aDecoder: NSCoder) {
        x = CGFloat(aDecoder.decodeDoubleForKey("x"))
        y = CGFloat(aDecoder.decodeDoubleForKey("y"))
    }
//    存数据
    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeDouble(Double(x), forKey: "x")
        aCoder.encodeDouble(Double(y), forKey: "y")
    }
}

编译运行结果如下:

Paste_Image.png

真彩色,类似取色工具 pod search colorpick

协议和扩展都要实现属性,实际上是计算属性 {set get}

为防止重构,写程序前要留后路

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,386评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,119评论 29 470
  • 她来了 又要走了 短暂而美丽 图/文:敬颐
    敬颐阅读 245评论 0 0
  • 对待生命要有感恩的心。 俗语说:滴水之恩,当涌泉相报。感恩是一种生活态度,是一种善于发现生活中的感动并能享受这一感...
    映卿阅读 932评论 0 0