我有一个CAShapelayer圆圈,我使用CABasicAnimation将进度圈从0旋转到360度,并将其设置为状态机中具有重置,播放,暂停和完成状态的倒数计时器。
现在,我可以播放或暂停并继续播放,直到计时器结束并且动画完成并且模型返回到其原始值,然后选择另一个倒数计时器值以动画开始。
但是,如果我在动画制作完成之前的任何时候播放并重置,它将取消,但是当我再次播放时,动画将不再起作用。我注意到出于某种原因,在动画完成之前重置后,我的strokeEnd不再从0.0开始,而是获得了看似任意的小数点值。我认为这是问题的根本原因,但我不知道为什么strokeEnd值是这些随机数。这是strokeEnd值的屏幕截图-https://imgur.com/a/YXmNkaK
这是我到目前为止所拥有的:
//draws CAShapelayer
func drawCircle() {}
//CAShapeLayer animation
func progressCircleAnimation(transitionDuration: TimeInterval, speed: Double, strokeEnd: Double) {
let fillLineAnimation = CABasicAnimation(keyPath: "strokeEnd")
fillLineAnimation.duration = transitionDuration
fillLineAnimation.fromValue = 0
fillLineAnimation.toValue = 1.0
fillLineAnimation.speed = Float(speed)
circleWithProgressBorderLayer.strokeEnd = CGFloat(strokeEnd)
circleWithProgressBorderLayer.add(fillLineAnimation, forKey: "lineFill")
}
//Mark: Pause animation
func pauseLayer(layer : CALayer) {
let pausedTime : CFTimeInterval = circleWithProgressBorderLayer.convertTime(CACurrentMediaTime(), from: nil)
circleWithProgressBorderLayer.speed = 0.0
circleWithProgressBorderLayer.timeOffset = pausedTime
}
//Mark: Resume CABasic Animation on CAShaperLayer at pause offset
func resumeLayer(layer : CALayer) {
let pausedTime = circleWithProgressBorderLayer.timeOffset
circleWithProgressBorderLayer.speed = 1.0;
circleWithProgressBorderLayer.timeOffset = 0.0;
circleWithProgressBorderLayer.beginTime = 0.0;
let timeSincePause = circleWithProgressBorderLayer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime
circleWithProgressBorderLayer.beginTime = timeSincePause;
}
//Mark: Tried to removeAnimation
func resetLayer(layer : CALayer) {
layer.removeAnimation(forKey: "lineFill")
circleWithProgressBorderLayer.strokeEnd = 0.0
}
这是我在状态机中进行设置的方式,以防错误与此有关:
@objc func timerIsReset() {
resetTimer()
let currentRow = timePickerView.selectedRow(inComponent: 0)
self.counter = self.Times[currentRow].amount
}
//Mark: action for RunningTimerState
@objc func timerIsStarted() {
runTimer()
}
//Mark: action for PausedTimerState
@objc func timerIsPaused() {
pauseTimer()
}
//Mark: action for TimerTimeRunOutState
func timerTimeRunOut() {
resetTimer()
}
func runTimer() {
if isPaused == true {
finishTime = Date().addingTimeInterval(-remainingTime)
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)
resumeLayer(layer: circleWithProgressBorderLayer)
} else if isPaused == false {
finishTime = Date().addingTimeInterval(counter)
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)
progressCircleAnimation(transitionDuration: counter, speed: 1.0, strokeEnd: self.completionPercentage)
}
}
//Mark: Pause Timer and pause CABasic Animation
func pauseTimer() {
timer.invalidate()
isPaused = true
remainingTime = -finishTime.timeIntervalSinceNow
completionPercentage = (counter + remainingTime) / counter
pauseLayer(layer: circleWithProgressBorderLayer)
}
func resetTimer() {
timer.invalidate()
isPaused = false
resetLayer(layer: circleWithProgressBorderLayer)
}
答案 0 :(得分:0)
可以说您的动画看起来像这样...
func runTimerMaskAnimation(duration: CFTimeInterval, fromValue : Double){
...
let path = UIBezierPath(roundedRect: circleBounds, cornerRadius:
circleBounds.size.width * 0.5)
maskLayer?.path = path.reversing().cgPath
maskLayer?.strokeEnd = 0
parentCALayer.mask = maskLayer
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.duration = duration
animation.fromValue = fromValue
animation.toValue = 0.0
maskLayer?.add(animation!, forKey: "strokeEnd")
}
如果我想在动画完成之前将计时器重新启动到原始位置,则可以删除动画,删除maskLayer,然后再次运行动画。
maskLayer?.removeAnimation(forKey: "strokeEnd")
maskLayer?.removeFromSuperlayer()
runTimerMaskAnimation(duration: 15, fromValue : 1)