Beginning Core Graphics(Swift)

来源:互联网 发布:windows桌面 编辑:程序博客网 时间:2024/05/21 09:44

本文内容来自于Beginning Core Graphics视频内容

Beginning Core Graphics(Swift)

Getting Started

关于drawRect(_:)方法

  • automatically called at the right time
  • don’t call this method directly
  • 可以通过setNeedsDisplay() or setNeedsDisplayInRect()

在本例子中给NumberView.swift自定义view,fill和stroke,最开始使用的rect是原始大小:

var lineWidth: CGFloat = 2override func drawRect(rect: CGRect) {    let path = UIBezierPath(ovalInRect: rect)    path.lineWidth = lineWidth    UIColor.redColor().setFill()    path.fill()    UIColor.blueColor().setStroke()    path.stroke()}

这样绘制的结果是,有部分的描边被view给裁剪掉了,如下:
这里写图片描述

这是因为a stroke is drawn half outside the line and half inside。正确的做法是:

    let insetRect = rect.insetBy(dx: lineWidth / 2, dy: lineWidth / 2)    let path = UIBezierPath(ovalInRect: insetRect)

Path路径

UIBezierPath的属性
lineCapStyle属性

这里写图片描述

lineJoinStyle属性

这里写图片描述

裁剪path
path.addClip()

本例是绘制一个指示器,效果如下:

这里写图片描述

使用UIBezierPath绘制圆弧,在使用贝塞尔曲线绘制一个指针,完整代码如下:

import UIKit@IBDesignableclass SummaryView: UIView {    var percentSpent:Float = 0    var lineWidth : CGFloat {        return bounds.height / 4    }    let margin :  CGFloat = 30    let pointerLayer = CAShapeLayer()    override func didMoveToSuperview() {        super.didMoveToSuperview()        layer.addSublayer(pointerLayer)    }    override func layoutSubviews() {        super.layoutSubviews()        let  path = createPointerPath()        pointerLayer.path = path.CGPath        pointerLayer.fillColor = darkViewColor.CGColor        pointerLayer.bounds = path.bounds        pointerLayer.anchorPoint = CGPointMake(0.5, 1)        pointerLayer.position = CGPointMake(bounds.midX, bounds.height - margin)    }    func createPointerPath() -> UIBezierPath {        let pointerHeight = bounds.height - lineWidth - margin        let pointerWidth: CGFloat = 18        //let pointerPath = UIBezierPath(ovalInRect: CGRectMake(0, 0, pointerWidth, pointerHeight))        let pointerPath = UIBezierPath()        pointerPath.moveToPoint(CGPointMake(pointerWidth / 2, 0))        pointerPath.addCurveToPoint(CGPointMake(pointerWidth / 2, pointerHeight),                            controlPoint1: CGPointMake(pointerWidth / 2, 0), controlPoint2: CGPointMake(-pointerWidth, pointerHeight))        pointerPath.addCurveToPoint(CGPointMake(pointerWidth / 2, 0),                                    controlPoint1: CGPointMake(pointerWidth * 2, pointerHeight), controlPoint2: CGPointMake(pointerWidth / 2, 0))        return pointerPath    }    override func drawRect(rect: CGRect) {        let arcCenter = CGPointMake(rect.midX, rect.height - margin)        let radius = rect.height - lineWidth / 2 - margin * 2        let startAngle : CGFloat = π        let endAngle : CGFloat = 0        let  path = UIBezierPath(arcCenter: arcCenter, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)        path.lineWidth = lineWidth        appGreenColor.setStroke()        path.stroke()    }}

关于贝塞尔曲线:
二阶贝塞尔曲线
这里写图片描述

参考:

  • 我们来谈谈贝塞尔曲线
  • http://cubic-bezier.com/

绘制圆弧的坐标系

这里写图片描述

在上一章的内容中绘制了一条宽为13的线,但是在iPhone6s或者iPhone6s Plus显示时,边界会有些模糊,如下:

这里写图片描述

在绘制线条时,定义起点和终点,如下绘制3个point的线

这里写图片描述

所以解决问题的关键是:
1.线宽是偶数
2.线宽是奇数,把线的位置向上或向下移动0.5个点

  override func drawRect(rect: CGRect) {    let path = UIBezierPath()    path.lineWidth = lineWidth    path.lineCapStyle = .Round    path.moveToPoint(CGPoint(x: 0, y: round(rect.height/2)+0.5))    let end = rect.width * CGFloat(percent)    path.addLineToPoint(CGPoint(x: end, y: round(rect.height/2)+0.5))    if percent >= 1.0 {      percentDangerLineColor.setStroke()    } else if percent > 0.8 {      percentWarningLineColor.setStroke()    } else {      percentLineColor.setStroke()    }    path.stroke()  }

context

context表示绘制的目的地

Drawing destination - view, pdf, image

  • UIGraphicsBeginContextWithOptions(size:opaque:scale:)
  • CGBitmapContextCreate(::::::_:)

path.addClip() it means that all drawing outside that path is excluded.

本例是绘制一个笑脸IconFun

import UIKitvar str = "Hello, playground"let size = CGSizeMake(400, 400)let rect = CGRect(origin: .zero, size: size)let backgroundColor = UIColor.redColor()let drawingColor = UIColor.blackColor()let lineWidth : CGFloat = 5.0UIGraphicsBeginImageContextWithOptions(size, false, 0.0)let context = UIGraphicsGetCurrentContext()let edge = UIBezierPath(roundedRect: rect.insetBy(dx: lineWidth / 2, dy: lineWidth / 2), cornerRadius: 50)CGContextSaveGState(context)edge.addClip()backgroundColor.setFill()UIRectFill(rect)CGContextRestoreGState(context)edge.lineWidth = lineWidthdrawingColor.setStroke()edge.stroke()let outerCircle = UIBezierPath(ovalInRect: CGRect(x: 46, y: 46, width: 310, height: 310))outerCircle.lineWidth = lineWidthouterCircle.stroke()let eye1 = UIBezierPath(ovalInRect: CGRect(x: 138, y: 126, width: 36, height: 72))eye1.lineWidth = lineWidtheye1.stroke()let eye2 = UIBezierPath(ovalInRect: CGRect(x: 223, y: 126, width: 36, height: 72))eye2.lineWidth = lineWidtheye2.stroke()let mouth = UIBezierPath()mouth.lineWidth = lineWidthmouth.moveToPoint(CGPointMake(136, 250))mouth.addLineToPoint(CGPointMake(265, 250))mouth.addCurveToPoint(CGPointMake(135, 250), controlPoint1: CGPoint(x:240, y:300), controlPoint2: CGPoint(x: 150, y: 300))mouth.closePath()mouth.lineJoinStyle = .Roundmouth.stroke()let path = UIBezierPath()path.appendPath(outerCircle)path.appendPath(eye1)path.appendPath(eye2)path.appendPath(mouth)let image = UIGraphicsGetImageFromCurrentImageContext()UIGraphicsEndImageContext()imageUIGraphicsBeginImageContextWithOptions(size, false, 0.0)path.stroke()let image2 = UIGraphicsGetImageFromCurrentImageContext()UIGraphicsEndImageContext()

效果如下:

这里写图片描述

使用Core Graphic来绘制

这里写图片描述

Device的坐标系原点在左上角,Core Graphic坐标系原点在右下角。当使用UI graphics context时,context会自动被翻转,所以所有的CGContext命令都会从左上角绘制。
然而当你使用CGBitmapContextCreate创建context时,坐标系原点是在右下角。

使用image.drawInRect(_:)绘制图片,图片会在指定的rect绘制。
但使用CGContextDrawImage(_:_:_:)绘制图片,图片会被翻转。

这里写图片描述

给path应用变换path.applyTransform(_:),例如,移动、缩放、旋转

这里写图片描述

本例是个path应用变换:

  private func scalePath(path:UIBezierPath, size:CGSize) {    // scale path - icons should all be same height    let scale = size.height / path.bounds.size.height * 0.5    path.applyTransform(CGAffineTransformMakeScale(scale, scale))    // move path to origin    path.applyTransform(CGAffineTransformMakeTranslation(-path.bounds.origin.x, -path.bounds.origin.y))    // move path into center    path.applyTransform(CGAffineTransformMakeTranslation(size.width/2 - path.bounds.width/2, size.height/2 - path.bounds.height/2))  }

PaintCode

使用PaintCode软件来绘制

0 0