美文网首页iOS面试
iOS中CAShapeLayer的介绍和使用

iOS中CAShapeLayer的介绍和使用

作者: Longshihua | 来源:发表于2018-11-26 18:39 被阅读0次

    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
    }
    
    屏幕快照 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
    }
    
    屏幕快照 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:是否是顺时针方向

    屏幕快照 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:控制点

    屏幕快照 2018-11-26 下午3.45.18.png

    三次贝塞尔曲线

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

    屏幕快照 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)
        }
    
    屏幕快照 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
    
    屏幕快照 2018-11-26 下午3.13.56.png
    • 描边开始和结束位置(strokeStart和strokeEnd)
    shapeLayer.strokeStart = 0.2
    shapeLayer.strokeEnd = 0.95
    
    屏幕快照 2018-11-26 下午3.09.26.png
    • 线模版(lineDashPattern)
     shapeLayer.lineDashPattern = [5,2,8,3]
    
    屏幕快照 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)
     }
    
    屏幕快照 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)
        }
    
    屏幕快照 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)
        }
    
    2018-11-26 16-51-01.2018-11-26 16_51_15.gif

    参考

    CAShapeLayer

    相关文章

      网友评论

        本文标题:iOS中CAShapeLayer的介绍和使用

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