1,什么是Core Graphics
(1)Core Graphics Framework 是一套基于 C 的 API 框架,使用了 Quartz 作为绘图引擎,可用于一切绘图操作。它提供了低级别、轻量级、高保真度的 2D 渲染。
(2)Quartz 2D 是 Core Graphics Framework 的一部分,是一个强大的二维图像绘制引擎。
(3)我们使用的 UIKit 库中所有 UI 组件其实都是由 CoreGraphics 绘制实现的。所以使用 Core Graphics 可以实现比 UIKit 更底层的功能。
(4)当我们引入 UIKit 框架时系统会自动引入 Core Graphics 框架,同时在 UIKit 内部还对一些常用的绘图 API 进行了封装,方便我们使用。 (比如:CGMutablePath 是 Core Graphics 的底层API,而 UIBezierPath 就是对 CGMutablePath 的封装。)
2,绘图的一般步骤
(1)获取绘图上下文
(2)创建并设置路径
(3)将路径添加到上下文
(4)设置上下文状态(如笔触颜色、宽度、填充色等等)
(5)绘制路径
===============context添加图片路径======================================
===============基础的绘图设置========
override func draw(_ rect: CGRect) {
super.draw(rect)
let ctx=UIGraphicsGetCurrentContext()
ctx?.move(to: CGPoint.init(x: 100, y: 100))//绘制起点
ctx?.addLine(to: CGPoint.init(x: 300, y: 100))//绘制第二个点
ctx?.addLine(to: CGPoint.init(x: 300, y: 300))//第三个点
ctx?.setLineCap(CGLineCap.butt)//设置线头的样式
ctx?.setLineJoin(CGLineJoin.bevel)//设置连接处的样式
ctx?.setLineWidth(10)//设置线宽
ctx?.setLineDash(phase: 5, lengths: [10,3])//设置虚线,phase是设置几段,lengths是设置每一个线段的长度和间隔
ctx?.addRect(CGRect.init(x: 0, y:0, width: 200, height: 200).insetBy(dx: 20, dy: 20))//相对于CGRect.init(x: 0, y:0, width: 200, height: 200)向内偏移x和y方向20,20
ctx?.setShadow(offset: CGSize.init(width: 3, height: 3), blur: 0.5, color: UIColor.blue.cgColor)//设置阴影
ctx?.setStrokeColor(UIColor.red.cgColor)//设置笔触的颜色
ctx?.closePath()//闭合路径
ctx?.strokePath()//绘制路径
}
==========填充fill========
let ctx=UIGraphicsGetCurrentContext()
ctx?.move(to: CGPoint.init(x: 100, y: 100))//绘制起点
ctx?.addLine(to: CGPoint.init(x: 300, y: 100))//绘制第二个点
ctx?.addLine(to: CGPoint.init(x: 300, y: 300))//第三个点
ctx?.setLineCap(CGLineCap.butt)//设置线头的样式
ctx?.setLineJoin(CGLineJoin.bevel)//设置连接处的样式
ctx?.setLineWidth(10)//设置线宽
ctx?.closePath()//闭合路径
ctx?.setFillColor(UIColor.red.cgColor)//设置填充颜色
ctx?.fillPath()//填充路径
================绘制长方形、正方形、圆形、椭圆形==========
let ctx=UIGraphicsGetCurrentContext()
ctx?.addRect(CGRect.init(x: 0, y:0, width: 200, height: 200))//绘制长方形,正方形,x,y是左上角的点
ctx?.addEllipse(in: CGRect.init(x: 100, y: 100, width: 200, height: 200))//正圆,x,y是圆的外切正方形的左上角的点
ctx?.addEllipse(in: CGRect.init(x: 100, y: 100, width: 200, height: 100))//椭圆,x,y是椭圆外切长方形的左上角的点
ctx?.strokePath()//绘制路径
==================绘图矩阵变形操作==========
注意:坐标变换操作必须要在添加图形之前,如果设置在添加图形之后的话会无效。
************平移=====
该方法相当于把原来位于 (0, 0) 位置的坐标原点平移到 (tx, ty) 点。在平移后的坐标系统上绘制图形时,所有坐标点的 X 坐标都相当于增加了 tx,所有点的 Y 坐标都相当于增加了 ty。
let ctx=UIGraphicsGetCurrentContext()
ctx?.translateBy(x: 50, y: 0)
ctx?.addRect(CGRect.init(x: 0, y:0, width: 200, height: 200))//绘制长方形,正方形,x,y是左上角的点
ctx?.strokePath()//绘制路径
***********************旋转****************
该方法控制坐标系统旋转 angle 弧度。在缩放后的坐标系统上绘制图形时,所有坐标点的 X、Y 坐标都相当于旋转了 angle弧度之后的坐标。
let ctx=UIGraphicsGetCurrentContext()
ctx?.rotate(by: 0.25*3.14)//旋转
ctx?.addRect(CGRect.init(x: 0, y:0, width: 200, height: 200))//绘制长方形,正方形,x,y是左上角的点
ctx?.strokePath()//绘制路径
**************缩放**************
该方法控制坐标系统在水平方向和垂直方向上进行缩放。在缩放后的坐标系统上绘制图形时,所有点的 X 坐标都相当于乘以 sx 因子,所有点的 Y 坐标都相当于乘以 sy 因子。
let ctx=UIGraphicsGetCurrentContext()
ctx?.scaleBy(x: 0.5, y: 0.5)//缩放到原来的0.5倍
ctx?.addRect(CGRect.init(x: 0, y:0, width: 200, height: 200))//绘制长方形,正方形,x,y是左上角的点
ctx?.strokePath()//绘制路径
***************贝塞尔曲线************
================CGMutablePath绘制图片路径-======================
***********二次贝塞尔曲线*********
//获取绘图上下文
let context = UIGraphicsGetCurrentContext()
//创建一个矩形,它的所有边都内缩3点
let drawingRect = self.bounds.insetBy(dx: 3, dy: 3)
//创建并设置路径
let path = CGMutablePath()
//移动起点
path.move(to: CGPoint(x: drawingRect.minX, y: drawingRect.maxY))
//二次贝塞尔曲线终点
let toPoint = CGPoint(x: drawingRect.maxX, y: drawingRect.maxY)
//二次贝塞尔曲线控制点
let controlPoint = CGPoint(x: drawingRect.midX, y: drawingRect.minY)
//绘制二次贝塞尔曲线
path.addQuadCurve(to: toPoint, control: controlPoint)
//添加路径到图形上下文
context?.addPath(path)
//设置笔触颜色
context?.setStrokeColor(UIColor.orange.cgColor)
//设置笔触宽度
context?.setLineWidth(6)
//绘制路径
context?.strokePath()
************三次贝塞尔曲线************
//获取绘图上下文
let context = UIGraphicsGetCurrentContext()
//创建一个矩形,它的所有边都内缩3点
let drawingRect = self.bounds.insetBy(dx: 3, dy: 3)
//创建并设置路径
let path = CGMutablePath()
//移动起点
path.move(to: CGPoint(x: drawingRect.minX, y: drawingRect.maxY))
//三次贝塞尔曲线终点
let toPoint = CGPoint(x: drawingRect.maxX, y: drawingRect.minY)
//三次贝塞尔曲线第1个控制点
let controlPoint1 = CGPoint(x: (drawingRect.minX+drawingRect.midX)/2, y: drawingRect.minY)
//三次贝塞尔曲线第2个控制点
let controlPoint2 = CGPoint(x: (drawingRect.midX+drawingRect.maxX)/2, y: drawingRect.maxY)
//绘制三次贝塞尔曲线
path.addCurve(to: toPoint, control1: controlPoint1, control2: controlPoint2)
//添加路径到图形上下文
context?.addPath(path)
//设置笔触颜色
context?.setStrokeColor(UIColor.orange.cgColor)
//设置笔触宽度
context?.setLineWidth(6)
//绘制路径
context?.strokePath()
================UIBezierPath设置图形路径===============
******stroke*******
let bz:UIBezierPath=UIBezierPath.init()//创建路径
bz.move(to: CGPoint.init(x: 10, y: 10))// 设置起点
bz.addLine(to: CGPoint.init(x: 100, y: 100))//添加另外一个点
bz.addLine(to: CGPoint.init(x: 150, y: 300))//添加另外一个点
bz.lineWidth=5
UIColor.red.setStroke()//设置路径颜色
bz.lineCapStyle=CGLineCap.butt
bz.lineJoinStyle=CGLineJoin.round
bz.close()//闭合路径
bz.stroke()//绘制一条线的时候用stroke,如果是图形时stroke就是空心的,fill就是填充
bz.removeAllPoints()//删除画布上所有的点,如果有stroke或fill操作,不起作用
**********fill*******
let bz:UIBezierPath=UIBezierPath.init()//相当于创建画布
bz.move(to: CGPoint.init(x: 10, y: 10))// 设置起点
bz.addLine(to: CGPoint.init(x: 100, y: 100))//添加另外一个点
bz.addLine(to: CGPoint.init(x: 150, y: 300))//添加另外一个点
bz.lineWidth=5
UIColor.red.setFill()//设置填充颜色
bz.lineCapStyle=CGLineCap.butt
bz.lineJoinStyle=CGLineJoin.round
bz.close()//闭合路径
bz.fill()//填充
****************绘制矩形**********
方法一:画四条直线
方法二:
let bz:UIBezierPath=UIBezierPath.init(rect: CGRect.init(x: 10, y: 10, width: 100, height: 100))//普通矩形
方法三: let bz:UIBezierPath=UIBezierPath.init(roundedRect: CGRect.init(x: 10, y: 10, width: 100, height: 100), cornerRadius: 5)//圆角矩形
方法四: let bz:UIBezierPath=UIBezierPath.init(roundedRect: CGRect.init(x: 10, y: 10, width: 100, height: 100), byRoundingCorners: UIRectCorner.topLeft, cornerRadii: CGSize(width: 10, height: 10))//单角圆弧矩形
bz.fill()
===========圆形、椭圆======
方法一:
let bz:UIBezierPath=UIBezierPath.init(ovalIn: CGRect.init(x: 100, y: 100, width: 50, height: 50))
方法二: /*
参数解释:
1.center: CGPoint 中心点坐标
2.radius: CGFloat 半径
3.startAngle: CGFloat 起始点所在弧度
4.endAngle: CGFloat 结束点所在弧度
5.clockwise: Bool 是否顺时针绘制
7.画圆时,没有坐标这个概念,根据弧度来定位起始点和结束点位置。M_PI即是圆周率。画半圆即(0,M_PI),代表0到180度。全圆则是(0,M_PI*2),代表0到360度
*/
let bz:UIBezierPath=UIBezierPath.init(arcCenter: CGPoint(x: 50, y: 50), radius: 50, startAngle: CGFloat(Double.pi) * 0, endAngle: CGFloat(Double.pi) * 2, clockwise: true)
bz.fill()
=========二阶、三阶贝塞尔曲线==========
//二阶贝塞尔曲线
let bz = UIBezierPath.init()
bz.move(to: CGPoint.init(x: 0, y: 0))
bz.addQuadCurve(to: CGPoint.init(x: 100, y: 100), controlPoint: CGPoint.init(x: 200, y: 400))
//三阶贝塞尔曲线
let bz1 = UIBezierPath.init()
bz1.move(to: CGPoint.init(x: 10, y: 10))
bz1.addCurve(to: CGPoint.init(x: 50, y: 50), controlPoint1: CGPoint.init(x: 50, y: 80), controlPoint2: CGPoint.init(x: 80, y: 120))
bz1.stroke()
=========CAShapeLayer绘图=======
1.CAShapeLayer继承CALayer,可以使用CALayer的全部属性.
2.CAShapeLayer需要配合贝塞尔曲线使用, CAShapeLayer需要贝塞尔曲线的path
3.使用CAShapeLayer与贝塞尔曲线可以实现不在view的drawRect方法中画出一下想要的图形, drawRect 是属于Core Graphics框架走CPU,比较耗性能. CAShapeLayer属于Core Animation框架,走GPU,动画渲染直接提交给手机GPU.
drawRect是UIView的方法,重写此方法可以完成绘制图形功能
第一步: //创建路径
let linePath = UIBezierPath()
//起点
linePath.move(to: CGPoint.init(x: 30, y: 30))
//添加其他点
linePath.addLine(to: CGPoint.init(x: 150, y: 150))
linePath.addLine(to: CGPoint.init(x: 180, y: 20))
//闭合路径
linePath.close()
第二部: //设施路径画布
let lineShape = CAShapeLayer()
lineShape.frame = CGRect.init(x: 10, y: 10, width: 350, height: 400)
//宽度
lineShape.lineWidth = 2
//线条之间点的样式
lineShape.lineJoin = kCALineJoinMiter
//线条结尾的样式
lineShape.lineCap = kCALineCapSquare
//路径颜色
lineShape.strokeColor = UIColor.red.cgColor
//获取贝塞尔曲线的路径------设置画布的路径
lineShape.path = linePath.cgPath
//填充色
lineShape.fillColor = UIColor.clear.cgColor
第三步: //把绘制的图放到layer上
self.layer.addSublayer(lineShape)
===========多条路径合并=====
//多条路径合并
let bz1 = UIBezierPath.init()
bz1.move(to: CGPoint.init(x: 10, y: 10))
bz1.addLine(to: CGPoint.init(x: 100, y: 10))
bz1.stroke()
let bz2 = UIBezierPath.init()
bz2.move(to: CGPoint.init(x: 10, y: 100))
bz2.addLine(to: CGPoint.init(x: 100, y: 200))
bz2.stroke()
bz1.append(bz2)//多条路径合并
============给cashaperlayer添加动画(绘制时候有动画效果)=
//CAShapeLayer,可以看做一个动画容器。把UIBezierPath绘制的路径放进去,点就会沿着这路径前进,加上颜色、动画等渲染后显示在界面上
let bz1 = UIBezierPath.init()
bz1.move(to: CGPoint.init(x: 10, y: 10))
bz1.addLine(to: CGPoint.init(x: 100, y: 10))
let shapeLayer = CAShapeLayer()
shapeLayer.path = bz1.cgPath //存入UIBezierPath的路径
shapeLayer.fillColor = UIColor.red.cgColor //设置填充色
shapeLayer.lineWidth = 2 //设置路径线的宽度
shapeLayer.strokeColor = UIColor.gray.cgColor //路径颜色
//如果想变为虚线设置这个属性,[实线宽度,虚线宽度],若两宽度相等可以简写为[宽度]
shapeLayer.lineDashPattern = [2]
//一般可以填"path" "strokeStart" "strokeEnd" 。。。。。。
let baseAnimation = CABasicAnimation(keyPath: "strokeEnd")
baseAnimation.duration = 2 //持续时间
baseAnimation.fromValue = 0 //开始值
baseAnimation.toValue = 2 //结束值
baseAnimation.repeatDuration = 5 //重复次数
shapeLayer.add(baseAnimation, forKey: nil) //给ShapeLayer添加动画
//显示在界面上
self.layer.addSublayer(shapeLayer)
1.********简易绘图*******
/**
绘图https://www.jianshu.com/p/1e4bc8378c36
*/
import UIKit
class LYBDrawView: UIView {
override func draw(_ rect: CGRect) {
//绘制椭圆,宽和高一样的时候就是正圆
// //1.UIKit方式绘制
// let p = UIBezierPath(ovalIn: CGRect.init(x: 0, y: 0, width: 100, height: 50))
// UIColor.blue.setFill()
// p.fill()
// //2.Core Graphic/QuartZ 2D方式绘制,(还有一种OpenGL ES)iOS用不着
// let ctx = UIGraphicsGetCurrentContext()!
// ctx.addEllipse(in: CGRect.init(x: 0, y: 0, width: 100, height: 50))
// ctx.setFillColor(UIColor.blue.cgColor)
// ctx.fillPath()
// //4.从上下文中获取图片
// UIGraphicsBeginImageContextWithOptions(CGSize.init(width: 100, height: 100), false, 0)
// let p = UIBezierPath.init(ovalIn: CGRect.init(x: 0, y: 0, width: 100, height: 50))
// UIColor.blue.setFill()
// p.fill()
// let image = UIGraphicsGetImageFromCurrentImageContext()
// UIGraphicsEndImageContext()
//
}
// // 3. 在UIView子类的drawLayer:inContext:方法中,使用下面的方法,draw方法还必须实现
// override func draw(_ layer: CALayer, in ctx: CGContext) {
// //方法3,
//// UIGraphicsPushContext(ctx) //将ctx设置为当前context
//// let p = UIBezierPath.init(ovalIn: CGRect.init(x: 0, y: 0, width: 100, height: 50))
//// UIColor.red.setFill()
//// p.fill()
//// UIGraphicsPushContext(ctx)
//
//
//
//
// }
}