iOS 动画:CADisplayLink 与 CAShapeLayer

iOS Animation: CADisplayLink vs CAShapeLayer

我正在编写一个计时器,类似于水平版时钟应用程序中可用的计时器,不同之处在于它从满开始到空。

我实现了计时器,它适用于更长的时间,但它无法足够快地制作动画以实现快速动画(我的目标是最快达到 400 毫秒的总动画时间),因为我使用 drawRect 方法制作动画。为了说明,这是我的计时器代码:

class SSTimerView: UIView {
    var timer: NSTimer?
    var startAngle: CGFloat = (CGFloat) (M_PI * 1.5)
    var endAngle: CGFloat = (CGFloat) (M_PI * 1.5) + (CGFloat) (M_PI * 2)
    var percent: CGFloat? = 100 

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func drawRect(rect: CGRect) {
        var bezierPath = UIBezierPath()
        //Create our arc with the correct angles
        bezierPath.addArcWithCenter(CGPointMake(rect.size.width/2, rect.size.height/2),
            radius: 130,
            startAngle: startAngle,
            endAngle: (endAngle - startAngle) * (percent! / 100.0) + startAngle,
            clockwise: true
        )
        //Set the display for the path and stroke it.
        bezierPath.lineWidth = 20
        Slide.sharedInstance.currentInstruction!.colorFamily.lighterColor.setStroke()
        bezierPath.stroke()
    }
}

我一直在研究 CADisplayLink,我认为它可能是一个可行的选择,但我也听说 CADisplayLink 并不适用于所有情况。这是其中之一吗?如果 CADisplayLink 在这里不合适,我应该使用什么 CA class?

如您所知,手动设置动画时 CADisplayLink 总是比 NSTimer 好。 (有关原因的讨论,请参阅 WWDC 2014 视频 Building Interruptible and Responsive Interactions,从视频开始大约 14 分钟开始。)因此,如果您坚持现有模式,一定要转向 CADisplayLink

但是如果你想为这条路径的绘图设置动画,CABasicAnimation就容易多了:

var shapeLayer: CAShapeLayer!

func addShapeLayer() {
    shapeLayer     = CAShapeLayer()
    let startAngle = CGFloat(M_PI * 1.5)
    let endAngle   = startAngle + CGFloat(M_PI * 2)

    let bezierPath = UIBezierPath()

    bezierPath.addArcWithCenter(CGPointMake(view.bounds.size.width/2, view.bounds.size.height/2),
        radius: 130.0,
        startAngle: startAngle,
        endAngle: endAngle,
        clockwise: true
    )

    shapeLayer.path        = bezierPath.CGPath
    shapeLayer.strokeColor = UIColor.blueColor().CGColor
    shapeLayer.fillColor   = UIColor.clearColor().CGColor
    shapeLayer.lineWidth   = 20.0

    view.layer.addSublayer(shapeLayer)
}

func animateShapeLayer() {
    let animation       = CABasicAnimation(keyPath: "strokeEnd")
    animation.duration  = 0.4
    animation.fromValue = 0.0
    animation.toValue   = 1.0
    shapeLayer.addAnimation(animation, forKey: "strokeEndAnimation")
}

如果您需要更多自定义行为,CADisplayLink 方法非常好,但如果您只想在一定时间内为路径的绘制设置动画,CABasicAnimation 是最简单的(并且很可能提供最佳性能)。