UIBezierPath和CAShapeLayer画线
(注意:该文章仅对Swift语言的画图部分的学习做简单总结,熟悉两种语言的小伙伴,可以随意)
<一>UIBezierPath(UIBezierPath官方介绍)UIBezierPath继承自NSObject对象。我们可以使用这个类来指定路径的几何形状。路径可以定义简单的形状,如矩形、椭圆和弧,也可以定义包含直线和曲线段混合的复杂多边形。定义形状之后,可以使用该类的其他方法在当前绘图上下文中呈现路径。
UIBezierPath中的方法
<1>创建UIBezierPath对象
(1)创建一个矩形路径的UIBezierPath对象
public convenience init(rect: CGRect)
(2)创建一个矩形路径的UIBezierPath对象,并且四个角为圆角,cornerRadius是圆角半径
public convenience init(roundedRect rect: CGRect, cornerRadius: CGFloat)
(3)创建一个矩形路径的UIBezierPath对象, byRoundingCorners可以设置某些角为圆角,cornerRadius是圆角半径
public convenience init(roundedRect rect: CGRect, byRoundingCorners corners: UIRectCorner, cornerRadii: CGSize)
//UIRectCornerd的枚举
public struct UIRectCorner : OptionSet {
public init(rawValue: UInt)
public static var topLeft: UIRectCorner { get }
public static var topRight: UIRectCorner { get }
public static var bottomLeft: UIRectCorner { get }
public static var bottomRight: UIRectCorner { get }
public static var allCorners: UIRectCorner { get }
}
(4)创建一个圆形路径的UIBezierPath对象,也可以用此方法画画圆弧,arcCenter:圆心,radius:半径,startAngle:圆形路径的起点,endAngle:圆形路径的终点,clockwise:方向是否是顺时针方向
public convenience init(arcCenter center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool)
(5)创建并返回一个新的UIBezierPath对象,该对象由核心图形路径的内容初始化。
public convenience init(cgPath CGPath: CGPath)
(6)创建一个UIBezierPath对象
public init()
(7)创建并返回一个新的UIBezierPath对象,该对象的路径是当前对象的路径的反向。
open func reversing() -> UIBezierPath
<2>构建UIBezierPath路径
(1) UIBezierPath路径的起点
open func move(to point: CGPoint)
(2)UIBezierPath路径沿途经过的点
open func addLine(to point: CGPoint)
(3) UIBezierPath画圆形或弧线,arcCenter:圆心,radius:半径,startAngle:圆形路径的起点,endAngle:圆形路径的终点,clockwise:方向是否是顺时针方向
open func addArc(withCenter center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool)
(4) UIBezierPath画二次贝塞尔曲线,endPoint:贝塞尔曲线终点,controlPoint:贝塞尔曲线控制点
open func addQuadCurve(to endPoint: CGPoint, controlPoint: CGPoint)
(5)UIBezierPath画二次贝塞尔曲线,endPoint:贝塞尔曲线终点,controlPoint1:第一个贝塞尔曲线控制点, controlPoint2:第二个贝塞尔曲线控制点
open func addCurve(to endPoint: CGPoint, controlPoint1: CGPoint, controlPoint2: CGPoint)
(6)关闭最近添加的子路径。
open func close()
(7)删除所有子路径。
open func removeAllPoints()
(8)将指定路径对象的内容追加到接收方的路径。
open func append(_ bezierPath: UIBezierPath)
(9)展示核心图形的路径。
open var cgPath: CGPath
(10)图形路径中的当前点
open var currentPoint: CGPoint { get }
<3>UIBezierPath的其他属性
**** UIBezierPath的线宽
open var lineWidth: CGFloat ()
****描边时路径端点的形状。
/* Line cap styles. */描边时路径端点的形状的枚举
public enum CGLineCap : Int32 {
case butt//表示path延伸到终点时 将不在延伸
case round//表示path延伸到终点时 画一个圆形 半径为UIBezierPath的线宽的一半
case square//表示path延伸到终点时 画一个正方形 边长为UIBezierPath的线宽
}
open var lineCapStyle: CGLineCap
****The shape of the joints between connected segments of a stroked path.(曲线路径连接部分之间的形状)
/* Line join styles. */
public enum CGLineJoin : Int32 {
case miter//路径连接部分 尖状
case round//路径连接部分 圆形
case bevel//路径连接部分 平型 没有尖状
}
open var lineJoinStyle: CGLineJoin
****The limiting value that helps avoid spikes at junctions between connected line segments.
open var miterLimit: CGFloat
****曲线路径段绘制精度
open var flatness: CGFloat
****指示绘制路径时是否使用奇偶绕线规则。
open var usesEvenOddFillRule: Bool
****设置路径的行描模式。
open func setLineDash(_ pattern: UnsafePointer?, count: Int, phase: CGFloat)
open func getLineDash(_ pattern: UnsafeMutablePointer?, count: UnsafeMutablePointer?, phase: UnsafeMutablePointer?)
<4>UIBezierPath画出路径
(1)使用当前绘图属性绘制路径所包围的区域。
open func fill()
(2)使用当前绘制属性沿接收方路径绘制一条线。
open func stroke()
(3)使用指定的混合模式和透明度值绘制接收方路径包围的区域。
open func fill(with blendMode: CGBlendMode, alpha: CGFloat)
(4)使用指定的混合模式和透明度值沿接收方路径绘制一条线。
open func stroke(with blendMode: CGBlendMode, alpha: CGFloat)
(5)将接收方路径包围的区域与当前图形上下文的裁剪路径相交,使结果形状成为当前的裁剪路径。
open func addClip()
(6)用于判断当前path组成的范围内,是否包含某个点(CGPoint)
open func contains(_ point: CGPoint) -> Bool
(7)The bounding rectangle of the path.
open var bounds: CGRect { get }
(8)使用指定的仿射变换矩阵对路径中的所有点进行变换。
open func apply(_ transform: CGAffineTransform)
<二> CAShapeLayer(CAShapeLayer官方介绍)CAShapeLayer是继承自CALayer类,属于QuartzCore框架。一般画图都需要UIBezierPath和CAShapeLayer结合来实现,UIBezierPath的作用主要是绘制路径,CAShapeLayer主要是对UIBezierPath的路径进行渲染,显示路径,并将CAShapeLayer对象添加到subLayer中,当然CAShapeLayer也可以完成动画等一系列操作,笔者总结一下画图过程中CAShapeLayer类中主要用到的方法。
CAShapeLayer中的方法
(1) CAShapeLayer的初始化
public init()
(2)定义要绘制的路径。
open var path: CGPath?
(3)路径的起点和终点连接的直线和路径上的其他线构成一块区域,fillColor是这块区域的填充色
open var fillColor: CGColor?
(4)填充路径时使用的填充规则。可选non-zero和even-odd两种,默认non-zero
open var fillRule: String
(5)路径的颜色
open var strokeColor: CGColor?
(6)线宽
open var lineWidth: CGFloat
(7)绘制路径时使用的斜接极限。可以做成动画。
/* The miter limit used when stroking the path. Defaults to ten.
* Animatable. */
open var miterLimit: CGFloat
(8)绘制路径终点的相对位置。可以做成动画。 区间为0到1
open var strokeEnd: CGFloat
上面是介绍了绘图的UIBezierPath和CAShapeLayer的基本属性和方法,我们只需要创建出一个UIBezierPath对象和CAShapeLayer对象,然后将UIBezierPath对象的cgPath属性赋值给CAShapeLayer对象的path属性,layer层添加CAShapeLayer对象即可绘制各种图形。即:
layer.path = path.cgPath
self.view.layer.addSublayer(layer)
<一>画直线
效果图:
实现
// 线的路径
let linePath = UIBezierPath.init()
//MARK: 动画
// 起点
linePath.move(to: CGPoint.init(x: 20, y: 300))
// 其他点
linePath.addLine(to: CGPoint.init(x: 200, y: 200))
//可以添加n多个点 可为折线,直线等
// linePath.addLine(to: CGPoint.init(x: 90, y: 70))
let lineLayer = CAShapeLayer.init()
lineLayer.lineWidth = 1
lineLayer.strokeColor = UIColor.green.cgColor
lineLayer.path = linePath.cgPath
lineLayer.fillColor = UIColor.clear.cgColor
//动画1
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 2
lineLayer.add(animation, forKey: "")
self.view.layer.addSublayer(lineLayer)
<二>画阴影图
自己的实现思路:路径的起点和终点连接的直线和路径上的其他线构成一块区域。利用CAShapeLayer的填充色完成
效果图:
实现
// 线的路径
let linePath = UIBezierPath.init()
//MARK: 动画
// 起点
linePath.move(to: CGPoint.init(x: 20, y: 400))
// 其他点
linePath.addLine(to: CGPoint.init(x: 20, y: 300))
linePath.addLine(to: CGPoint.init(x: 30, y: 200))
linePath.addLine(to: CGPoint.init(x: 50, y: 267))
linePath.addLine(to: CGPoint.init(x: 100, y: 267))
linePath.addLine(to: CGPoint.init(x: 150, y: 200))
linePath.addLine(to: CGPoint.init(x: 200, y: 188))
linePath.addLine(to: CGPoint.init(x: 200, y: 400))
let lineLayer = CAShapeLayer.init()
lineLayer.lineWidth = 1
lineLayer.strokeColor = UIColor.green.cgColor
lineLayer.path = linePath.cgPath
lineLayer.fillColor = UIColor.orange.withAlphaComponent(0.3).cgColor//闭合区域的填充色
//动画1
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 2
lineLayer.add(animation, forKey: "")
self.view.layer.addSublayer(lineLayer)
<三>画多边形
自己的实现思路:绘制完成路径后,使用path.close()//图层封闭方法。
效果图:
实现
let path = UIBezierPath.init()
////layer起点
path.move(to: CGPoint.init(x: 30, y: NavigationBarHeight+50))
////layer整条路径上经过的其他点 用此方法也可以画多边形
path.addLine(to: CGPoint.init(x: 30, y: NavigationBarHeight+100))
path.addLine(to: CGPoint.init(x: 200, y: NavigationBarHeight+100))
// path.addLine(to: CGPoint.init(x: 200, y: NavigationBarHeight+50))
path.close()//图层封闭
let layer = CAShapeLayer.init()
layer.path = path.cgPath
layer.lineWidth = 1
layer.strokeColor = UIColor.orange.cgColor
layer.fillColor = UIColor.clear.cgColor//填充色
self.view.layer.addSublayer(layer)
<四>画圆形或椭圆
自己的实现思路:画圆形或椭圆,可以使用绘制一个view,为其添加蒙版效果实现,若视图为长方形 ,则绘制椭圆 ,正方形,则为圆形。另外还可以使用UIBezierPath类中的open func addArc(withCenter center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool)画圆。
效果图:
实现
class PaintCilcleViewVC: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
////画圆形或椭圆
drawCircleView()
//画圆形或椭圆 2
drawCircleViewSecond()
}
/**
画圆形或椭圆 1
*/
func drawCircleView() {
// 需要圆视图 若视图为长方形 则绘制椭圆 正方形,则为圆形
let circleView = UIView.init(frame: CGRect.init(x: (kScreenWidth-200)/2, y: NavigationBarHeight*2, width: 200, height: 100))
circleView.backgroundColor = UIColor.orange
self.view.addSubview(circleView)
// 线的路径
let path = UIBezierPath.init(ovalIn:circleView.bounds)
let pathLayer = CAShapeLayer.init()
pathLayer.lineWidth = 1
pathLayer.strokeColor = UIColor.green.cgColor
pathLayer.path = path.cgPath
pathLayer.fillColor = nil
circleView.layer.addSublayer(pathLayer)
circleView.layer.mask = pathLayer // layer 的 mask属性,添加蒙版
}
/**
画圆形
*/
func drawCircleViewSecond() {
let path = UIBezierPath.init()
path.addArc(withCenter: CGPoint.init(x: kScreenWidth/2, y: 500), radius: 30, startAngle: 0, endAngle: 2*CGFloat(Double.pi), clockwise: true)
let layer = CAShapeLayer.init()
layer.lineWidth = 1
layer.strokeColor = UIColor.green.cgColor
layer.path = path.cgPath
layer.fillColor = nil
self.view.layer.addSublayer(layer)
}
}
<五>画圆角矩形
自己的实现思路:首先需要我们创建一个需要绘制圆角的View,绘制四个圆角,可以使用public convenience init(roundedRect rect: CGRect, cornerRadius: CGFloat)该方法,如果想要实现某个角为圆角或者多个角为圆角,可以使用public convenience init(roundedRect rect: CGRect, byRoundingCorners corners: UIRectCorner, cornerRadii: CGSize)方法。
效果图:
实现
class PaintRoundedRectangleVC: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
//四角切圆角
drawQuadRangle()
//单角切圆角
drawUnicornous()
}
/**
四角切圆角
*/
func drawQuadRangle() {
// 需要画圆角矩形
let view = UIView.init(frame: CGRect.init(x: (kScreenWidth-200)/2, y: NavigationBarHeight, width: 100, height: 100))
view.backgroundColor = UIColor.orange
self.view.addSubview(view)
//线的路径
let path = UIBezierPath.init(roundedRect: view.bounds, cornerRadius: 20)
let layer = CAShapeLayer.init()
layer.lineWidth = 1
layer.strokeColor = UIColor.green.cgColor
layer.path = path.cgPath
view.layer.mask = layer
}
/**
单角切圆角 (多个角进行圆角切)
*/
func drawUnicornous() {
// 需要画圆角矩形
let view = UIView.init(frame: CGRect.init(x: (kScreenWidth-200)/2, y: NavigationBarHeight+150, width: 100, height: 100))
view.backgroundColor = UIColor.orange
self.view.addSubview(view)
//线的路径
//此方法可以用来对多个角进行圆角切
// let path = UIBezierPath.init(roundedRect: view.bounds, byRoundingCorners: UIRectCorner(rawValue: UIRectCorner.RawValue(UInt8(UIRectCorner.topLeft.rawValue) | UInt8(UIRectCorner.bottomRight.rawValue))) , cornerRadii: CGSize.init(width: 20, height: 0))
//此方法可以用来对单个角进行圆角切
let path = UIBezierPath.init(roundedRect: view.bounds, byRoundingCorners: UIRectCorner.topLeft, cornerRadii: CGSize.init(width: 20, height: 0))
let layer = CAShapeLayer.init()
layer.lineWidth = 1
layer.strokeColor = UIColor.green.cgColor
layer.path = path.cgPath
view.layer.mask = layer
}
}
<六>画弧线
自己的实现思路:画圆是从0绘制到2pi的位置,画弧线就是角度可以自己随意绘制。
效果图:
实现
class PaintTrajectoryViewVC: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
//在矩形中画一条圆弧
paintTrajectory()
//折线和弧线构成的曲线
lineAndTrajectoryView()
}
/**
在矩形中画一条圆弧
*/
func paintTrajectory() {
let view = UIView.init(frame: CGRect.init(x: (kScreenWidth-200)/2, y: NavigationBarHeight, width: 100, height: 100))
view.backgroundColor = UIColor.orange
self.view.addSubview(view)
//线的路径
let viewCenter = CGPoint.init(x: view.frame.width/2, y: view.frame.height/2)// 画弧的中心点,相对于view
let path = UIBezierPath.init(arcCenter: viewCenter, radius: 33, startAngle: CGFloat(0), endAngle: CGFloat(1.6*Double.pi), clockwise: true)
let layer = CAShapeLayer.init()
layer.lineWidth = 1
layer.strokeColor = UIColor.green.cgColor
layer.fillColor = nil
layer.path = path.cgPath
view.layer.addSublayer(layer)
}
/**
折线和弧线构成的曲线
*/
func lineAndTrajectoryView() {
let view = UIView.init(frame: CGRect.init(x: (kScreenWidth-200)/2, y: NavigationBarHeight+200, width: 150, height: 150))
view.backgroundColor = UIColor.orange
self.view.addSubview(view)
//线的路径
let viewCenter = CGPoint.init(x: view.frame.width/2, y: view.frame.height/2)// 画弧的中心点,相对于view
let path = UIBezierPath.init()
path.move(to: CGPoint.init(x: 0, y: 0))
path.addLine(to: viewCenter)
// 添加一条弧线
path.addArc(withCenter: viewCenter, radius: 50, startAngle: 0, endAngle: CGFloat(Double.pi), clockwise: true)
let layer = CAShapeLayer.init()
layer.lineWidth = 1
layer.strokeColor = UIColor.green.cgColor
layer.fillColor = nil
layer.path = path.cgPath
view.layer.addSublayer(layer)
}
}
<七>绘制饼状图
自己的实现思路:绘制饼状图其实就是绘制n个圆弧,可以将其CAShapeLayer的fillColor设置为透明色,strokeColor是圆弧的颜色,可以设置为自己想要的颜色,通过设置lineWidth路径的宽度来调整圆弧的大小。饼状图也可是实现点击效果,重写func touchesBegan(_ touches: Set, with event: UIEvent?)方法来实现。
效果图:
实现
/*饼状图*/
class RYQPieChartView: UIView {
//设置圆点
var centerPoint:CGPoint!
var radius:CGFloat!
var layerWidth = 40*m6Scale//圆环宽度
var startAngle:Float = 0
var endAngle:Float = 0
var allValue:Float = 0
var dataSource = [456, 567, 559]
var colors = [UIColor.green, UIColor.orange, UIColor.gray]
var outBezerArrs = [Any]()
var outLayers = [Any]()
override init(frame: CGRect) {
super.init(frame: frame)
radius = frame.size.height*0.4-layerWidth
centerPoint = CGPoint.init(x: frame.size.width/2, y: frame.size.height/2)
//画图
drawPieChartView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
/**
画图
*/
extension RYQPieChartView {
func drawPieChartView() {
for index in 0...dataSource.count-1 {
let value = dataSource[index]
allValue = allValue+Float(value)
}
//for循环画图
for index in 0...dataSource.count-1 {
bezierPaint(index: index)
}
}
//贝塞尔和CASherLayer画图
func bezierPaint(index:Int) {
let targetValue = dataSource[index]
let ratioString = String(format: "%.5f", Float(targetValue)/Float(allValue))
endAngle = startAngle + (Float(ratioString)!-0.005)*2*Float(Double.pi)
//bezierPath形成闭合的扇形路径 外弧形
let bezierOutPath = UIBezierPath.init()
// 添加一条弧线
bezierOutPath.addArc(withCenter: centerPoint, radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat(endAngle), clockwise: true)
//////外弧形渲染
let outLayer = CAShapeLayer.init()
outLayer.lineWidth = layerWidth
outLayer.fillColor = clear.cgColor
outLayer.strokeColor = colors[index].cgColor
outLayer.path = bezierOutPath.cgPath
self.layer.addSublayer(outLayer)
let start = dataSource[index]
let scaleString = String(format: "%.5f", Float(start)/Float(allValue))
startAngle = startAngle+(Float(scaleString)!-1)*2*Float(Double.pi)
//动画1
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 1
outLayer.add(animation, forKey: "")
outBezerArrs.append(bezierOutPath)
outLayers.append(outLayer)
}
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
let touch:UITouch = ((touches as NSSet).anyObject()! )as!UITouch
let point = touch.location(in: self)
var start:Float = 0
var end:Float = 0
for index in 0...outBezerArrs.count-1 {
let targetValue = dataSource[index]
let ratioString = String(format: "%.5f", Float(targetValue)/Float(allValue))
end = start + (Float(ratioString)!-0.005)*2*Float(Double.pi)
let bezierOutPath = outBezerArrs[index] as! UIBezierPath
let outLayer = outLayers[index] as! CAShapeLayer
layerWidth = 40*m6Scale
if bezierOutPath.contains(point) {
layerWidth = 60*m6Scale
}
//移除path上的所有点 重新绘制
bezierOutPath.removeAllPoints()
// 添加一条弧线
bezierOutPath.addArc(withCenter: centerPoint, radius: radius, startAngle: CGFloat(start), endAngle: CGFloat(end), clockwise: true)
//外弧形渲染
outLayer.path = bezierOutPath.cgPath
outLayer.lineWidth = layerWidth
let newstart = dataSource[index]
let scaleString = String(format: "%.5f", Float(newstart)/Float(allValue))
start = start+(Float(scaleString)!-1)*2*Float(Double.pi)
}
}
}
<八>不规则渐变色图形
自己的实现思路:使用CGContextRef属性,获取上下文生成图片,再次绘制UIBezierPath,将生成的图片填充到CAShapeLayer的填充色中。
效果图:
实现
class IrregularGradientVC: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
//绘制UIBezierPath路径
let path = UIBezierPath.init()
path.move(to: CGPoint.init(x: 0, y: NavigationBarHeight))
path.addLine(to: CGPoint.init(x: 0, y: 150+NavigationBarHeight))
path.addCurve(to: CGPoint.init(x: kScreenWidth, y: 150+NavigationBarHeight), controlPoint1: CGPoint.init(x: kScreenWidth*0.3, y: 200+NavigationBarHeight), controlPoint2: CGPoint.init(x: kScreenWidth*0.8, y: 350+NavigationBarHeight))
path.addLine(to: CGPoint.init(x: kScreenWidth, y: NavigationBarHeight))
//绘制渐变 图片
let img = drawLinearGradient(startColor: UIColor.green.cgColor, endColor: UIColor.red.cgColor)
let layer = CAShapeLayer.init()
//本质上生成一张渐变色图片 作为layer的填充背景
layer.fillColor = UIColor.init(patternImage: img).cgColor
layer.path = path.cgPath
self.view.layer.addSublayer(layer)
}
/**
绘制渐变
*/
func drawLinearGradient(startColor:CGColor, endColor:CGColor) -> UIImage {
//创建CGContextRef
UIGraphicsBeginImageContext(self.view.bounds.size)
let context = UIGraphicsGetCurrentContext()
let path = UIBezierPath.init()
path.move(to: CGPoint.init(x: 0, y: NavigationBarHeight))
path.addLine(to: CGPoint.init(x: 0, y: kScreenHeight))
path.addLine(to: CGPoint.init(x: kScreenWidth, y: kScreenHeight))
path.addLine(to: CGPoint.init(x: kScreenWidth, y: 0))
let colorSpace = CGColorSpaceCreateDeviceRGB()
let locations = [CGFloat(0.0), CGFloat(1.0)]
let colors = [startColor, endColor]
let gradient = CGGradient.init(colorsSpace: colorSpace, colors: colors as CFArray, locations: locations)
let pathRect: CGRect = path.cgPath.boundingBox
//具体方向可根据需求修改
let startPoint = CGPoint.init(x: pathRect.minX, y: pathRect.midY)
let endPoint = CGPoint.init(x: pathRect.maxX, y: pathRect.midY)
context?.saveGState()
context?.addPath(path.cgPath)
context?.clip()
context?.drawLinearGradient(gradient!, start: startPoint, end: endPoint, options: CGGradientDrawingOptions(rawValue: 0))
context?.restoreGState()
//获取绘制的图片
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img!
}
}
<九>二次贝塞尔曲线
效果图:
实现
class QuadRaticBezierVC: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
quadRaticBezierView()
sameEndPointQuadRaticBezierView()
}
/**
总结:起点和终点的距离越小,趋向控制点结束越早,趋向终点开始越早,曲线弧度越大。
起点终点相同,控制点不同
*/
func quadRaticBezierView() {
let view = UIView.init(frame: CGRect.init(x: (kScreenWidth-200)/2, y: NavigationBarHeight, width: 200, height: 200))
view.backgroundColor = UIColor.orange
self.view.addSubview(view)
// 绿色二次贝塞尔曲线
let greenPath = UIBezierPath.init()
greenPath.move(to: CGPoint.init(x: 0, y: 100))
let end1Point = CGPoint.init(x: 200, y: 50)
//二次贝塞尔曲线
greenPath.addQuadCurve(to: end1Point, controlPoint: CGPoint.init(x: 100, y: 200))
let layer1 = CAShapeLayer.init()
layer1.lineWidth = 1
layer1.strokeColor = UIColor.green.cgColor
layer1.fillColor = nil
layer1.path = greenPath.cgPath
view.layer.addSublayer(layer1)
// 红色二次贝塞尔曲线
let redPath = UIBezierPath.init()
redPath.move(to: CGPoint.init(x: 0, y: 100))
let end2Point = CGPoint.init(x: 100, y: 50)
// 二次贝塞尔曲线
redPath.addQuadCurve(to: end2Point, controlPoint: CGPoint.init(x: 100, y: 200))
let layer2 = CAShapeLayer.init()
layer2.lineWidth = 1
layer2.strokeColor = UIColor.red.cgColor
layer2.fillColor = nil
layer2.path = redPath.cgPath
view.layer.addSublayer(layer2)
}
/**
总结:控制点与起点和终点所在直线偏移距离越大,曲线弧度越大。
*/
func sameEndPointQuadRaticBezierView() {
let view = UIView.init(frame: CGRect.init(x: (kScreenWidth-200)/2, y: NavigationBarHeight+300, width: 200, height: 200))
view.backgroundColor = UIColor.orange
self.view.addSubview(view)
let startPoint = CGPoint.init(x: 0, y: 100)
let endPoint = CGPoint.init(x: 200, y: 50)
// 绿色二次贝塞尔曲线
let greenPath = UIBezierPath.init()
greenPath.move(to: startPoint)
//二次贝塞尔曲线
greenPath.addQuadCurve(to: endPoint, controlPoint: CGPoint.init(x: 100, y: 200))
let layer1 = CAShapeLayer.init()
layer1.lineWidth = 1
layer1.strokeColor = UIColor.green.cgColor
layer1.fillColor = nil
layer1.path = greenPath.cgPath
view.layer.addSublayer(layer1)
// 红色二次贝塞尔曲线
let redPath = UIBezierPath.init()
redPath.move(to: CGPoint.init(x: 0, y: 100))
// 二次贝塞尔曲线
redPath.addQuadCurve(to: endPoint, controlPoint: CGPoint.init(x: 100, y: 150))
let layer2 = CAShapeLayer.init()
layer2.lineWidth = 1
layer2.strokeColor = UIColor.red.cgColor
layer2.fillColor = nil
layer2.path = redPath.cgPath
view.layer.addSublayer(layer2)
}
}
<十>三次贝塞尔曲线
效果图:
实现
/**
三次贝塞尔曲线 比较于二次贝塞尔曲线 多了一个控制点
- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2
三次贝赛尔曲线,起点用 moveToPoint方法给出;endPoint:贝赛尔曲线终点;controlPoint1:控制点1;controlPoint2:控制点2;
曲线是由起点趋向控制点1,之后趋向控制点2,最后到达终点(不会经过控制点)的曲线。在起点和终点所在直线方向上,曲线在起点和控制点1之间,趋向控制点1;在控制点2和终点之间,趋向控制点2.控制点与起点和终点所在直线的偏移影响曲线的偏移程度
*/
class TripleBezierVC: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
let view = UIView.init(frame: CGRect.init(x: (kScreenWidth-200)/2, y: NavigationBarHeight, width: 200, height: 200))
view.backgroundColor = UIColor.orange
self.view.addSubview(view)
let startPoint = CGPoint.init(x: 0, y: 100)
let endPoint = CGPoint.init(x: 200, y: 50)
// 绿色三次贝塞尔曲线
let path = UIBezierPath.init()
path.move(to: startPoint)
//三次贝塞尔曲线
path.addCurve(to: endPoint, controlPoint1: CGPoint.init(x: 10, y: 0), controlPoint2: CGPoint.init(x: 70, y: 180))
//在加 可画出n次贝塞尔曲线
// path.addCurve(to: startPoint, controlPoint1: CGPoint.init(x: 40, y: 40), controlPoint2: CGPoint.init(x: 90, y: 120))
let layer = CAShapeLayer.init()
layer.lineWidth = 1
layer.strokeColor = UIColor.green.cgColor
layer.fillColor = nil
layer.path = path.cgPath
//动画1
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 2
layer.add(animation, forKey: "")
view.layer.addSublayer(layer)
}
}
想下载Demo的小伙伴,Demo下载,觉得有用的点个星吧。有什么错误和不足的地方也欢迎指正。