美文网首页iOS开发知识小集
贝塞尔曲线-UIBezierPath

贝塞尔曲线-UIBezierPath

作者: 小凡凡520 | 来源:发表于2019-03-08 15:22 被阅读53次
一、UIBezierPath常用的API
  • 常用路径参数
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    
    UIColor.red.set()// 同时设置路径颜色和路径的填充色
    UIColor.red.setStroke()// 设置路径颜色
    UIColor.red.setFill()// 设置路径的填充色
}



open var lineWidth: CGFloat// 路径宽度

open var lineCapStyle: CGLineCap// 路径开始和结尾的样式

open var lineJoinStyle: CGLineJoin// 路径转角处的样式


/**
 * 两条线交汇处内角和外角之间的最大距离, 只有当连接点样式为 kCGLineJoinMiter
 * 时才会生效,最大限制为10
 * 我们都知道, 两条直线相交时, 夹角越小, 斜接长度就越大.
 * 该属性就是用来控制最大斜接长度的.
 * 当我们设置了该属性, 如果斜接长度超过我们设置的范围,
 * 则连接处将会以 kCGLineJoinBevel 连接类型进行显示.
 */
open var miterLimit: CGFloat // Used when lineJoinStyle is kCGLineJoinMiter


/**
 * 该属性用来确定渲染曲线路径的精确度.
 * 该属性的值用来测量真实曲线的点和渲染曲线的点的最大允许距离.
 * 值越小, 渲染精度越高, 会产生相对更平滑的曲线, 但是需要花费更
 * 多的计算时间. 值越大导致则会降低渲染精度, 这会使得渲染的更迅
 * 速. flatness 的默认值为 0.6.
 * Note: 大多数情况下, 我们都不需要修改这个属性的值. 然而当我们
 *       希望以最小的消耗去绘制一个临时的曲线时, 我们也许会临时增
 *       大这个值, 来获得更快的渲染速度.
 */

open var flatness: CGFloat

lineCapStyle

1116725-8b2529910b256c71.png

lineJoinStyle

1116725-832c3a65deb1dca7.png

miterLimit

2452150-d6647c67c61e87c6.png.jpeg 2452150-051f956b8581ffc4.png.jpeg
  • 绘制路径的方法

把路径当前点移动到指定的点point

open func move(to point: CGPoint)

画一条直线

open func addLine(to point: CGPoint)

以路径当前点为起始点,point为结束点,给当前路径添加一条直线
添加完之后会自动将路径的当前点设置为结束点point

画一段圆弧

@available(iOS 4.0, *)
open func addArc(withCenter center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool)

以路径当前点为起始点,center为中心,radius为半径,startAngle为画圆弧的起始角度(单位为弧度,水平方向的右侧为0和2π,水平方向的左侧为π),endAngle为圆弧的结束角度(单位为弧度),clockwise是否顺时针;
添加完之后会自动将路径的当前点设置为结束点
1116725-6d39c6551992b832.png.jpeg

画一条二次贝塞尔曲线

open func addQuadCurve(to endPoint: CGPoint, controlPoint: CGPoint)

以路径当前点为起始点,endPoint为结束点,controlPoint为控制点,给当前路径添加一条二次贝塞尔曲线
添加完之后会自动将路径的当前点设置为结束点endPoint

画一条三次贝塞尔曲线

open func addCurve(to endPoint: CGPoint, controlPoint1: CGPoint, controlPoint2: CGPoint)

以路径当前点为起始点,endPoint为结束点,controlPoint1和controlPoint2为两个控制点,给当前路径添加一条三次贝塞尔曲线
添加完之后会自动将路径的当前点设置为结束点endPoint

画一条虚线

open func setLineDash(_ pattern: UnsafePointer<CGFloat>?, count: Int, phase: CGFloat)

pattern:
是一个C语言里的数组,如CGFloat pattern[] = {10, 10};,它代表实现和空白交替的模式:如{10, 10}代表从起点开始先画一个10pt的小实线,然后空白10pt,然后再画一个10pt的小实线,如此循环画下去,直到路径结束;再如{10, 20, 30}代表从起点开始先画一个10pt的小实线,然后空白20pt,然后再画一个30pt的小实线,然后再空白10pt,然后画一个20pt的小实线,然后再空白30pt,如此循环画下去,直到路径结束。

count
是pattern数组的长度

phase
相位,默认为0,设置为几就代表虚线整体上相对phase=0的情况需要向左移动几

闭合路径

open func close()

这个方法会在最后一个点和第一个点之间连接一条直线来将路径闭合
路径闭合完之后会自动将路径的当前点设置为路径的第一个点
  • 快速绘制特殊路径

画一个矩形

public convenience init(rect: CGRect)

这个方法以rect的origin为起点,顺时针绘制出一个矩形
绘制完成后自动闭合路径,将结束点作为路径的当前点

画一个圆角矩形(四个角都会圆)

public convenience init(roundedRect rect: CGRect, cornerRadius: CGFloat)

画一个指定圆角的矩形(指定角会圆)

public convenience init(roundedRect rect: CGRect, byRoundingCorners corners: UIRectCorner, cornerRadii: CGSize)

cornerRadii是个CGSize的类型,暂时把半径设置为size的width值
但是如果size中比较大的值超过了矩形短边的一半,则圆角会采取矩形短边的一半为半径。

画一段圆弧

public convenience init(arcCenter center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool)

给定一个矩形,画出其内切圆或椭圆

public convenience init(ovalIn rect: CGRect)
  • 渲染路径

空心渲染路径

open func stroke()

这个方法用来空心渲染路径
并且在渲染路径之前,会自动复制一份最纯洁的图形上下文,因此我们不需要考虑图层上下文的事,只需要专注于使用UIBezierPath来绘制路径就可以了。

实心渲染路径

open func fill()

这个方法用来实心渲染路径,即渲染路径包围的部分,并不包含路径本身,因此如果路径很宽的话,是不会渲染路径本身的
并且在渲染路径之前,会自动复制一份最纯洁的图形上下文,因此我们不需要考虑图层上下文的事,只需要继续使用UIBezierPath来绘制路径就可以了
  • 路径的仿射变化
open func apply(_ transform: CGAffineTransform)

我们可以用这个对路径进行仿射变换,但是要注意对路径的仿射变化其实是对整个图层进行了仿射变换
  • 移除路径上所有的点(或者说移除路径)
open func removeAllPoints()

这个方法用来移除路径上所有的点或者说移除路径
  • 剪裁效果
open func addClip()

调用一下这个方法,我们可以把一个对象绘制到一个路径所覆盖的区域内,就可以达到对对象的剪裁效果
只要调用了这个方法,那么显示的范围就被限定为该bezierPath所包围的范围了,此时无论往上下文中绘制什么东西,只要超出了这个范围的就都不会显示
二、UIBezierPath代码实现
  • 画一条直线
class CustomView: UIView {
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        let bezierPath = UIBezierPath()
        UIColor.red.setStroke()
        bezierPath.lineWidth = 11
        bezierPath.lineCapStyle = .round
        bezierPath.lineJoinStyle = .round
        
        bezierPath.move(to: CGPoint(x: 150, y: 250))
        bezierPath.addLine(to: CGPoint(x: 300, y: 700))
        
        bezierPath.stroke()
    }
}
Simulator Screen Shot - iPhone XR - 2019-03-07 at 23.12.59.png
  • 画圆弧
class CustomView: UIView {
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        let bezierPath = UIBezierPath()
        UIColor.red.setStroke()
        bezierPath.lineWidth = 11
        bezierPath.lineCapStyle = .round
        bezierPath.lineJoinStyle = .round
        bezierPath.move(to: CGPoint(x: 150, y: 100))
        bezierPath.addArc(withCenter: CGPoint(x: 100, y: 100), radius: 50, startAngle: 0, endAngle: CGFloat(M_PI), clockwise: true)
        bezierPath.stroke()
    }
}
Simulator Screen Shot - iPhone XR - 2019-03-08 at 11.18.10.png
  • 画圆
class CustomView: UIView {
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        // 画圆弧
        let bezierPath = UIBezierPath()
        UIColor.red.setStroke()
        bezierPath.lineWidth = 11
        bezierPath.lineCapStyle = .round
        bezierPath.lineJoinStyle = .round
        bezierPath.move(to: CGPoint(x: 150, y: 100))
        bezierPath.addArc(withCenter: CGPoint(x: 100, y: 100), radius: 50, startAngle: 0, endAngle: CGFloat(M_PI * 2), clockwise: true)
        bezierPath.stroke()
        
        // 画圆
        let bezierPath0 = UIBezierPath(ovalIn: CGRect(x: 10, y: 100, width: 400, height: 300))
        UIColor.red.setStroke()
        bezierPath0.lineWidth = 11
        bezierPath0.lineCapStyle = .round
        bezierPath0.lineJoinStyle = .round
        bezierPath0.move(to: CGPoint(x: 150, y: 100))
        bezierPath0.stroke()
        
        // 画内切圆
        let bezierPath1 = UIBezierPath(ovalIn: CGRect(x: 10, y: 100, width: 400, height: 300))
        UIColor.red.setFill()
        bezierPath1.lineWidth = 11
        bezierPath1.lineCapStyle = .round
        bezierPath1.lineJoinStyle = .round
        bezierPath1.move(to: CGPoint(x: 150, y: 100))
        bezierPath1.fill()
    }
}
Simulator Screen Shot - iPhone XR - 2019-03-08 at 11.39.30.png
  • 画矩形
class CustomView: UIView {
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        // 画矩形
        let bezierPath = UIBezierPath()
        UIColor.red.setStroke()
        bezierPath.lineWidth = 11
        bezierPath.lineJoinStyle = .round
        bezierPath.lineCapStyle = .round
        bezierPath.move(to: CGPoint(x: 100, y: 100))
        bezierPath.addLine(to: CGPoint(x: 200, y: 100))
        bezierPath.addLine(to: CGPoint(x: 200, y: 200))
        bezierPath.addLine(to: CGPoint(x: 100, y: 200))
        bezierPath.close()// 或者[bezierPath addLineToPoint:CGPointMake(100, 100)];
        bezierPath.stroke()
        
        
        let bezierPath1 = UIBezierPath(rect: CGRect(x: 250, y: 100, width: 100, height: 100))
        UIColor.red.setStroke()
        bezierPath1.stroke()
        
        // 画圆角矩形
        let bezierPath2 = UIBezierPath(roundedRect: CGRect(x: 100, y: 250, width: 100, height: 100), cornerRadius: 10)
        UIColor.red.setStroke()
        bezierPath2.stroke()
        
        // 画指定圆角的矩形
        let bezierPath3 = UIBezierPath(roundedRect: CGRect(x: 100, y: 400, width: 100, height: 100), byRoundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 40, height: 0))
        UIColor.red.setStroke()
        bezierPath3.stroke()
    }
}
Simulator Screen Shot - iPhone XR - 2019-03-08 at 11.35.11.png
  • 画二次贝塞尔曲线和三次贝塞尔曲线
class CustomView: UIView {
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        // 画一条二次贝塞尔曲线
        let bezierPath = UIBezierPath()
        UIColor.red.setStroke()
        bezierPath.lineWidth = 11
        bezierPath.move(to: CGPoint(x: 100, y: 100))
        bezierPath.addQuadCurve(to: CGPoint(x: 300, y: 100), controlPoint: CGPoint(x: 200, y: 200))
        bezierPath.stroke()
        
        // 画一条三次贝塞尔曲线
        let bezierPath1 = UIBezierPath()
        UIColor.red.setStroke()
        bezierPath1.lineWidth = 11
        bezierPath1.move(to: CGPoint(x: 100, y: 300))
        bezierPath1.addCurve(to: CGPoint(x: 300, y: 300), controlPoint1: CGPoint(x: 150, y: 350), controlPoint2: CGPoint(x: 250, y: 250))
        bezierPath1.stroke()
    }
}
  • 画一条虚线
class CustomView: UIView {
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        let bezierPath = UIBezierPath()
        UIColor.red.setStroke()
        bezierPath.setLineDash([10.0,10.0], count: 2, phase: 0)
        bezierPath.move(to: CGPoint(x: 100, y: 100))
        bezierPath.addLine(to: CGPoint(x: 300, y: 100))
        bezierPath.stroke()
        
        let bezierPath1 = UIBezierPath()
        UIColor.red.setStroke()
        bezierPath1.setLineDash([10,20,30], count: 3, phase: 0)
        bezierPath1.move(to: CGPoint(x: 100, y: 120))
        bezierPath1.addLine(to: CGPoint(x: 300, y: 120))
        bezierPath1.stroke()
        
        let bezierPath2 = UIBezierPath()
        UIColor.red.setStroke()
        bezierPath2.setLineDash([10,10], count: 3, phase: 5)
        bezierPath2.move(to: CGPoint(x: 100, y: 140))
        bezierPath2.addLine(to: CGPoint(x: 300, y: 140))
        bezierPath2.stroke()
        
        let bezierPath3 = UIBezierPath(arcCenter: self.center, radius: 100, startAngle: 0, endAngle: CGFloat(M_PI * 2), clockwise: true)
        UIColor.red.setStroke()
        bezierPath3.lineWidth = 11
        bezierPath3.setLineDash([1,10], count: 2, phase: 0)
        bezierPath3.stroke()
    }
}
Simulator Screen Shot - iPhone XR - 2019-03-08 at 14.10.52.png
  • 贝塞尔曲线的仿射变换
class CustomView: UIView {
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        let bezierPath = UIBezierPath(rect: CGRect(x: 250, y: 100, width: 100, height: 100))
        UIColor.red.setStroke()
        bezierPath.lineWidth = 11
        bezierPath.lineCapStyle = .round
        bezierPath.lineJoinStyle =  .round
        bezierPath.apply(CGAffineTransform(rotationAngle: CGFloat(M_PI_4)))
        bezierPath.stroke()
    }
}
Simulator Screen Shot - iPhone XR - 2019-03-08 at 14.14.50.png
  • 剪裁路径覆盖的区域
class CustomView: UIView {
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        // 把图片切成任意你想要的形状显示
        let bezierPath = UIBezierPath(roundedRect: CGRect(x: 100, y: 100, width: 100, height: 100), byRoundingCorners: [.topLeft,.bottomRight], cornerRadii: CGSize(width: 40, height: 0))
        UIColor.red.setStroke()
        bezierPath.stroke()
        bezierPath.addClip()// 剪裁路径覆盖的区域
        
        let image = UIImage(named: "1.png")
        image?.draw(at: CGPoint(x: 100, y: 100))
    }
}
Simulator Screen Shot - iPhone XR - 2019-03-08 at 14.20.05.png
  • 利用- (void)addLineToPoint:(CGPoint)point;画数学函数曲线
class CustomView: UIView {
    
    fileprivate var bezierPath:UIBezierPath!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        
        self.bezierPath = UIBezierPath()
        self.bezierPath.lineWidth = 1// 笔的粗细
        
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(pan(_:)))
        // 一个指头画
        panGesture.maximumNumberOfTouches = 1
        self.addGestureRecognizer(panGesture)
    }
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        // 笔的颜色
        UIColor.red.setStroke()
        
        // 渲染出曲线
        self.bezierPath.stroke()
    }
    
    @objc func pan(_ panGesture:UIGestureRecognizer) {
        // 获取平移到的点
        let currentPoint = panGesture.location(in: self)
        
        if panGesture.state == .began {
            // 设置起始点
            self.bezierPath.move(to: currentPoint)
        } else {
            // 连接平移点
            self.bezierPath.addLine(to: currentPoint)
        }
        
        // 触发-drawRect:方法
        self.setNeedsDisplay()
    }
}
1116725-6f6e6ac04e599eba.gif

相关文章

网友评论

    本文标题:贝塞尔曲线-UIBezierPath

    本文链接:https://www.haomeiwen.com/subject/hjdkpqtx.html