iOS面试

iOS中CAShapeLayer的介绍和使用

2018-11-26  本文已影响0人  Longshihua

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

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

属性

    // 路径
    open var path: CGPath?
    // 路径填充颜色,默认黑色,可动画属性
    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]?

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

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

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
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进行绘制,很容易就显示矩形了,因为默认的填充颜色为黑色,所以看到的是黑色的矩形。

shapeLayer.fillColor = UIColor.red.cgColor
屏幕快照 2018-11-26 下午2.40.27.png
shapeLayer.strokeColor = UIColor.black.cgColor
屏幕快照 2018-11-26 下午2.41.48.png

默认为1的边线宽度

shapeLayer.lineWidth = 5
屏幕快照 2018-11-26 下午2.43.25.png
shapeLayer.lineWidth = 20 // 增大边框,方便观察
shapeLayer.lineJoin = kCALineJoinRound
屏幕快照 2018-11-26 下午3.13.56.png
shapeLayer.strokeStart = 0.2
shapeLayer.strokeEnd = 0.95
屏幕快照 2018-11-26 下午3.09.26.png
 shapeLayer.lineDashPattern = [5,2,8,3]
屏幕快照 2018-11-26 下午4.02.47.png

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

绘制圆形

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

上一篇下一篇

猜你喜欢

热点阅读