Swift 使用CADisplayLink设置动画的CAShapeLayer笔划未完成

Swift 使用CADisplayLink设置动画的CAShapeLayer笔划未完成,swift,Swift,我已经设置了一个CADisplayLink,它调用以下drawCircle()函数在10秒内绘制一个圆路径动画: func drawCircle() { currentDuration = currentDuration + displayLink.duration circleLayer.strokeEnd = min(CGFloat(currentDuration/maxDuration), 1) if (currentDuration >= maxDurat

我已经设置了一个
CADisplayLink
,它调用以下
drawCircle()
函数在10秒内绘制一个圆路径动画:

func drawCircle() {
    currentDuration = currentDuration + displayLink.duration
    circleLayer.strokeEnd = min(CGFloat(currentDuration/maxDuration), 1)

    if (currentDuration >= maxDuration) {
        stopCircleAnimation()
    }
}

func stopCircleAnimation() {
    let pausedTime = circleLayer.convertTime(CACurrentMediaTime(), fromLayer: nil)
    circleLayer.speed = 0
    circleLayer.timeOffset = pausedTime
}
其中,
currentDuration
是经过的时间,
maxDuration
等于10。这工作正常,除非
currentDuration>=maxDuration
。即使strokeEnd设置为1,它也不会完全完成圆。这是为什么

编辑


我认为这可能与
circleLayer
speed
属性有关。如果我将其设置为更高的值,例如10,则圆圈完全闭合。

找到了答案–设置strokeEnd属性时禁用动画:

CATransaction.begin()
CATransaction.setDisableActions(true)
circleLayer.strokeEnd = min(CGFloat(currentDuration/maxDuration), 1)
CATransaction.commit()

这是因为设置
CAShapeLayer
strokeEnd
会将隐式动画生成为新值。然后,在此动画完成之前,将层的速度设置为零,从而“暂停”动画,使其看起来“不完整”

虽然您可以通过
setDisableActions
禁用隐式动画来解决问题,但您可能应该考虑在这里使用
CADisplayLink
是否真的合适。核心动画的设计初衷是通过生成自己的中间步骤来为您生成和运行动画,因此,为什么不通过显式或隐式动画来实现层的
strokeEnd

下面是一个如何使用隐式动画执行此操作的示例:

CATransaction.begin()
CATransaction.setAnimationDuration(10)

// if you really want a linear timing function – generally makes the animation look ugly
CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear))

circleLayer.strokeEnd = 1
CATransaction.commit()
let anim = CABasicAnimation(keyPath: "strokeEnd")
anim.fromValue = 0
anim.toValue = 1
anim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
anim.duration = 10
circleLayer.addAnimation(anim, forKey: "strokeEndAnim")

// update model layer value
CATransaction.begin()
CATransaction.setDisableActions(true)
circleLayer.strokeEnd = 1
CATransaction.commit()
或者,如果希望将其作为显式动画:

CATransaction.begin()
CATransaction.setAnimationDuration(10)

// if you really want a linear timing function – generally makes the animation look ugly
CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear))

circleLayer.strokeEnd = 1
CATransaction.commit()
let anim = CABasicAnimation(keyPath: "strokeEnd")
anim.fromValue = 0
anim.toValue = 1
anim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
anim.duration = 10
circleLayer.addAnimation(anim, forKey: "strokeEndAnim")

// update model layer value
CATransaction.begin()
CATransaction.setDisableActions(true)
circleLayer.strokeEnd = 1
CATransaction.commit()

实际上,我需要使用CADisplayLink,因为我将它与视频计时结合使用,所以需要尽可能精确。但是,关于禁用CATTransaction操作,您是对的(正如我在您发布答案之前发现的)。不过我会接受你的回答,因为你说得太详细了。