更新:NSTimer方法现在可以使用,但性能却很高。问题现在缩小到没有 NSTimers的方法。
我正在尝试动画“按住”互动动画。在跟踪了大量的SO答案之后,我大部分都遵循@ david-rönnqvist控制动画时间的方法。如果我使用Slider传递layer.timeOffset
。
但是,我似乎无法找到一种在按住手势时不断更新相同动画的好方法。动画要么没有开始,只显示开始帧,要么在某些时候结束并拒绝重新开始。
任何人都可以帮助实现以下效果,没有我正在尝试的可怕的NSTimer方法吗?
这是我当前努力的Github repo。
如上所述,以下代码运行良好。它由滑块触发并完成其工作。
func animationTimeOffsetToPercentage(percentage: Double) {
if fillShapeLayer == nil {
fillShapeLayer = constructFillShapeLayer()
}
guard let fillAnimationLayer = fillShapeLayer, let _ = fillAnimationLayer.animationForKey("animation") else {
print("Animation not found")
return
}
let timeOffset = maximumDuration * percentage
print("Set animation to percentage \(percentage) with timeOffset: \(timeOffset)")
fillAnimationLayer.timeOffset = timeOffset
}
然而,使用NSTimers的以下方法可行,但性能却令人难以置信。我正在寻找一种不使用NSTimer的方法。
func beginAnimation() {
if fillShapeLayer == nil {
fillShapeLayer = constructFillShapeLayer()
}
animationTimer?.invalidate()
animationTimer = NSTimer.schedule(interval: 0.1, repeats: true, block: { [unowned self] () -> Void in
if self.layer.timeOffset >= 1.0 {
self.layer.timeOffset = self.maximumDuration
}
else {
self.layer.timeOffset += 0.1
}
})
}
func reverseAnimation() {
guard let fillAnimationLayer = fillShapeLayer, let _ = fillAnimationLayer.animationForKey("animation") else {
print("Animation not found")
return
}
animationTimer?.invalidate()
animationTimer = NSTimer.schedule(interval: 0.1, repeats: true, block: { [unowned self] () -> Void in
if self.layer.timeOffset <= 0.0 {
self.layer.timeOffset = 0.0
}
else {
self.layer.timeOffset -= 0.1
}
})
}
答案 0 :(得分:1)
使用滑块时,使用fillAnimationLayer
图层进行动画
fillAnimationLayer.timeOffset = timeOffset
但是,在beginAnimation
和reverseAnimation
函数中,您使用的是self.layer
。
尝试在计时器块中将self.layer.timeOffset
替换为self.fillShapeLayer!.timeOffset
。
答案 1 :(得分:1)
解决方案是双重的;
确保动画在完成时不会自行移除并保留其最终帧。使用以下代码行轻松完成;
animation.fillMode = kCAFillModeForwards
animation.removedOnCompletion = false
困难的部分;你必须删除原始动画并开始一个从正确的点开始的新的反向动画。这样做,给我以下代码;
func setAnimation(layer: CAShapeLayer, startPath: AnyObject, endPath: AnyObject, duration: Double)
{
// Always create a new animation.
let animation: CABasicAnimation = CABasicAnimation(keyPath: "path")
if let currentAnimation = layer.animationForKey("animation") as? CABasicAnimation {
// If an animation exists, reverse it.
animation.fromValue = currentAnimation.toValue
animation.toValue = currentAnimation.fromValue
let pauseTime = layer.convertTime(CACurrentMediaTime(), fromLayer: nil)
// For the timeSinceStart, we take the minimum from the duration or the time passed.
// If not, holding the animation longer than its duration would cause a delay in the reverse animation.
let timeSinceStart = min(pauseTime - startTime, currentAnimation.duration)
// Now convert for the reverse animation.
let reversePauseTime = currentAnimation.duration - timeSinceStart
animation.beginTime = pauseTime - reversePauseTime
// Remove the old animation
layer.removeAnimationForKey("animation")
// Reset startTime, to be when the reverse WOULD HAVE started.
startTime = animation.beginTime
}
else {
// This happens when there is no current animation happening.
startTime = layer.convertTime(CACurrentMediaTime(), fromLayer: nil)
animation.fromValue = startPath
animation.toValue = endPath
}
animation.duration = duration
animation.fillMode = kCAFillModeForwards
animation.removedOnCompletion = false
layer.addAnimation(animation, forKey: "animation")
}
这个Apple article解释了如何进行适当的暂停和恢复动画,并将其转换为与反向动画一起使用。