iOS中CAShapeLayer的介绍和使用

CAShapeLayer是图形layer层,我们可以自定义这个层的形状。CAShapeLayer是一个通过矢量图形而不是bitmap来绘制的图层子类。指定诸如颜色和线宽等属性,用CGPath来定义想要绘制的图形,最后CAShapeLayer就自动渲染出来了。当然,也可以用Core Graphics直接向原始的CALyer的内容中绘制一个路径,相比之下,使用CAShapeLayer有以下一些优点:

  • 渲染快速。CAShapeLayer使用了硬件加速,绘制同一图形会比用Core Graphics快很多。
  • 高效使用内存。一个CAShapeLayer不需要像普通CALayer一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。
  • 不会被图层边界剪裁掉。一个CAShapeLayer可以在边界之外绘制。图层路径不会像在使用Core Graphics的普通CALayer一样被剪裁掉。
  • 不会出现像素化。当把CAShapeLayer放大,或是用3D透视变换将其离相机更近时,它不像一个有寄宿图的普通图层一样变得像素化。

CAShapeLayer可以用来绘制所有能够通过CGPath来表示的形状。这个形状不一定要闭合,图层路径也不一定要不间断的,事实上可以在一个图层上绘制好几个不同的形状。

属性

  • 指定图像的路径(Specifying the Shape Path)
    // 路径
    open var path: CGPath?
  • 样式属性(Shape Style Properties)
    // 路径填充颜色,默认黑色,可动画属性
    open var fillColor: CGColor?

    // 路径填充规则,奇偶或者非零,默认是非零
    open var fillRule: CAShapeLayerFillRule

    // 描边颜色,默认为nil,可动画属性
    open var strokeColor: CGColor?

    // 描边的起点和终点
    open var strokeStart: CGFloat // 它表示描线开始的地方占总路径的百分比
    open var strokeEnd: CGFloat // 表示绘制结束的地方站总路径的百分比

    // 描边的宽,默认为1,可动画属性
    open var lineWidth: CGFloat

    // 最大斜街长度
    open var miterLimit: CGFloat

    // 线端点的样式
    open var lineCap: CAShapeLayerLineCap

    // 线拐点的样式
    open var lineJoin: CAShapeLayerLineJoin

    // 边线模版的起点
    open var lineDashPhase: CGFloat

    // 设置边线的样式,默认为实线
    open var lineDashPattern: [NSNumber]?
  • lineDashPattern

这是一个NSNumber的数组,索引从1开始记,奇数位数值表示实线长度,偶数位数值表示空白长度。系统会按照数值自动重复设置虚线。

  • miterLimit

最大斜接长度。斜接长度指的是在两条线交汇处和外交之间的距离。只有lineJoin属性为kCALineJoinMiter时miterLimit才有效。边角的角度越小,斜接长度就会越大。为了避免斜接长度过长,我们可以使用miterLimit属性。如果斜接长度超过miterLimit的值,边角会以lineJoin的“bevel”即kCALineJoinBevel类型来显示

  • CAShapeLayerLineJoin
extension CAShapeLayerLineJoin {
    @available(iOS 3.0, *)
    public static let miter: CAShapeLayerLineJoin

    @available(iOS 3.0, *)
    public static let round: CAShapeLayerLineJoin

    @available(iOS 3.0, *)
    public static let bevel: CAShapeLayerLineJoin
}
iOS中CAShapeLayer的介绍和使用_第1张图片
屏幕快照 2018-11-26 下午2.56.32.png
  • CAShapeLayerLineCap
extension CAShapeLayerLineCap {
    @available(iOS 3.0, *)
    public static let butt: CAShapeLayerLineCap

    @available(iOS 3.0, *)
    public static let round: CAShapeLayerLineCap

    @available(iOS 3.0, *)
    public static let square: CAShapeLayerLineCap
}
iOS中CAShapeLayer的介绍和使用_第2张图片
屏幕快照 2018-11-26 下午2.56.38.png

UIBezierPath

UIBezierPath 专门是用来绘制路径的,常和CAShapeLayer一起配合使用

  • 绘制矩形
 public convenience init(rect: CGRect)
  • 绘制椭圆形
 public convenience init(ovalIn rect: CGRect)
  • 绘制圆角
 public convenience init(roundedRect rect: CGRect, cornerRadius: CGFloat) // rounds all corners with the same horizontal and vertical radius

 public convenience init(roundedRect rect: CGRect, byRoundingCorners corners: UIRectCorner, cornerRadii: CGSize)
  • 绘制圆弧
public convenience init(arcCenter center: CGPoint,
                   radius: CGFloat,
                   startAngle: CGFloat,
                   endAngle: CGFloat,
                   clockwise: Bool)

open func addArc(withCenter center: CGPoint,
                  radius: CGFloat,
                  startAngle: CGFloat,
                  endAngle: CGFloat,
                  clockwise: Bool)

center:圆弧的中心
radius:圆弧半角
startAngle:起始点的角度(相对坐标系0)
endAngle:结束点的角度
endAngle:是否是顺时针方向

iOS中CAShapeLayer的介绍和使用_第3张图片
屏幕快照 2018-11-26 下午3.46.00.png
  • 根据路径绘制
public convenience init(cgPath CGPath: CGPath)
  • 绘制线段
// 添加路径起点
open func move(to point: CGPoint)
// 添加直线到另外一个点    
open func addLine(to point: CGPoint)
  • 绘制贝塞尔曲线
// 三次贝塞尔曲线
open func addCurve(to endPoint: CGPoint, controlPoint1: CGPoint, controlPoint2: CGPoint)
// 二次贝塞尔曲线
open func addQuadCurve(to endPoint: CGPoint, controlPoint: CGPoint)

二次贝塞尔曲线

endPoint:贝塞尔曲线终点
controlPoint:控制点

iOS中CAShapeLayer的介绍和使用_第4张图片
屏幕快照 2018-11-26 下午3.45.18.png

三次贝塞尔曲线

endPoint:贝塞尔曲线终点
controlPoint1:控制点1
controlPoint2:控制点2

iOS中CAShapeLayer的介绍和使用_第5张图片
屏幕快照 2018-11-26 下午3.45.43.png

实战

绘制矩形

  func drawRect() {
        let path = UIBezierPath(rect: CGRect(x: 100, y: 100, width: 100, height: 100))
        let shapeLayer = CAShapeLayer()
        // 设置路径
        shapeLayer.path = path.cgPath
        view.layer.addSublayer(shapeLayer)
    }
iOS中CAShapeLayer的介绍和使用_第6张图片
屏幕快照 2018-11-26 下午2.37.43.png

可以看到我们仅仅是创建了一个路径,然后使用CAShapeLayer进行绘制,很容易就显示矩形了,因为默认的填充颜色为黑色,所以看到的是黑色的矩形。

  • 修改填充颜色(fillColor)
shapeLayer.fillColor = UIColor.red.cgColor
屏幕快照 2018-11-26 下午2.40.27.png
  • 设置描边颜色(strokeColor)
shapeLayer.strokeColor = UIColor.black.cgColor
屏幕快照 2018-11-26 下午2.41.48.png

默认为1的边线宽度

  • 设置线宽
shapeLayer.lineWidth = 5
屏幕快照 2018-11-26 下午2.43.25.png
  • 拐点样式(lineJoin)
shapeLayer.lineWidth = 20 // 增大边框,方便观察
shapeLayer.lineJoin = kCALineJoinRound
iOS中CAShapeLayer的介绍和使用_第7张图片
屏幕快照 2018-11-26 下午3.13.56.png
  • 描边开始和结束位置(strokeStart和strokeEnd)
shapeLayer.strokeStart = 0.2
shapeLayer.strokeEnd = 0.95
iOS中CAShapeLayer的介绍和使用_第8张图片
屏幕快照 2018-11-26 下午3.09.26.png
  • 线模版(lineDashPattern)
 shapeLayer.lineDashPattern = [5,2,8,3]
iOS中CAShapeLayer的介绍和使用_第9张图片
屏幕快照 2018-11-26 下午4.02.47.png

这句话的意思是说这个虚线由四部分组成:

  • 第一段实线长度为5
  • 画完长度为5像素的实线之后,空2像素
  • 空完2像素之后,再画8像素的实线
  • 画完长度为8像素的实线之后,空3像素
  • 然后重复这个数组中的数值,一直不停的绘画。

绘制圆形

func drawARC() {
    let shapeLayer = CAShapeLayer()
    shapeLayer.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
    shapeLayer.fillColor = UIColor.orange.cgColor
    shapeLayer.lineWidth = 3
    shapeLayer.strokeColor = UIColor.black.cgColor
    // 画弧
    let path = UIBezierPath(arcCenter: shapeLayer.position,
                               radius: 100,
                               startAngle: 0,
                               endAngle: CGFloat(2 * Float.pi),
                               clockwise: true)
    shapeLayer.path = path.cgPath
    // 设置居中
    shapeLayer.position = view.center
    view.layer.addSublayer(shapeLayer)
 }
iOS中CAShapeLayer的介绍和使用_第10张图片
屏幕快照 2018-11-26 下午3.18.55.png

绘制花朵

  func drawFlower() {
        // 创建shapeLayer
        let shapeLayer = CAShapeLayer()
        shapeLayer.position = view.center
        // 创建一个可变路径
        let path = CGMutablePath()
        stride(from: 0, to: CGFloat.pi * 2, by: CGFloat.pi / 6).forEach {
            angle in
            var transform  = CGAffineTransform(rotationAngle: angle)

            // 绘制椭圆路径
            let petal = CGPath(ellipseIn: CGRect(x: -20, y: 0, width: 40, height: 100),
                               transform: &transform)

            path.addPath(petal)
        }
        // 指定绘制的路径
        shapeLayer.path = path
        // 边框颜色
        shapeLayer.strokeColor = UIColor.red.cgColor
        // 路径的填充颜色
        shapeLayer.fillColor = UIColor.yellow.cgColor
        // 填充规则
        shapeLayer.fillRule = kCAFillRuleEvenOdd
        view.layer.addSublayer(shapeLayer)
    }
iOS中CAShapeLayer的介绍和使用_第11张图片
屏幕快照 2018-11-26 下午3.24.11.png

进度条动画

  func ovalAnimation() {
        // 创建CAShapeLayer
        let shapeLayer = CAShapeLayer()
        shapeLayer.bounds = CGRect(x: 0, y: 0, width: 100, height: 100)
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.strokeColor = UIColor.red.cgColor
        shapeLayer.lineWidth = 2.0

        // 添加路径
        let path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 100, height: 100))
        shapeLayer.path = path.cgPath

        shapeLayer.position = view.center
        view.layer.addSublayer(shapeLayer)

        // 添加动画
        let animation = CABasicAnimation(keyPath: "strokeEnd")
        animation.duration = 2.0
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
        animation.fromValue = 0.0
        animation.toValue = 1.0
        animation.fillMode = kCAFillModeForwards
        animation.isRemovedOnCompletion = false
        shapeLayer.add(animation, forKey: nil)
    }
iOS中CAShapeLayer的介绍和使用_第12张图片
2018-11-26 16-51-01.2018-11-26 16_51_15.gif

参考

CAShapeLayer

你可能感兴趣的:(iOS中CAShapeLayer的介绍和使用)