CAKeyFrameAnimation не является линейным для значений, превышающих PI
У меня возникли проблемы с пониманием, почему анимация не работает так, как ожидалось. Что я делаю, так это:
Создать
UIBezierPath
с помощью дуги, чтобы переместить метку вдоль этого пути и анимировать обводку путей.//Start Point is -.pi /2 to let the Arc start at the top. //self.progress = Value between 0.0 and 1.0 let path : UIBezierPath = UIBezierPath.init(arcCenter: CGPoint.init(x: self.bounds.width * 0.5, y: self.bounds.height * 0.5), radius: self.bounds.width * 0.5, startAngle: -.pi / 2, endAngle: (2 * self.progress * .pi) - (.pi / 2), clockwise: true) return path
Добавить этот путь к
CAShapeLayer
circlePathLayer.frame = bounds circlePathLayer.path = self.path.cgPath circlePathLayer.strokeStart = 0 circlePathLayer.strokeEnd = 1
Анимируйте свойство strokeEnd с помощью
CABasicAnimation
let animation = CABasicAnimation(keyPath: "strokeEnd") animation.repeatCount = HUGE animation.fromValue = 0.0 animation.toValue = 1.0 animation.duration = self.animationDuration animation.isRemovedOnCompletion = false animation.fillMode = kCAFillModeBoth
Анимируйте свойство position моего ярлыка с помощью
CAKeyFrameAnimation
let animationScore = CAKeyframeAnimation(keyPath: "position") //some things I tried to fix //animationScore.timingFunctions = [CAMediaTimingFunction(controlPoints: 0.250, 0.250, 0.750, 0.750)] //animationScore.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionLinear) animationScore.path = self.path.cgPath animationScore.duration = self.animationDuration animationScore.isRemovedOnCompletion = false animationScore.fillMode = kCAFillModeBoth animationScore.repeatCount = HUGE
Добавить мои анимации в слой и метку
self.circlePathLayer.add(animation, forKey: nil) self.scoreLabel.layer.add(animationScore, forKey: nil)
Моя проблема: для значений ProgressValues больше 0,75 моя метка не движется с линейной скоростью. Значения больше 0,75 означают, что моя дуга больше, чем PI. При значениях менее 0,75 моя анимация работает нормально, а метки и штрихи имеют одинаковую скорость и находятся друг над другом.
Пожалуйста, игнорируйте 100% в ярлыке в этом gif, мой прогресс был на уровне 0,76.
Вы видите, что мой ярлык замедляется после трех четвертей моего круга.
Я надеюсь, что кто-то может помочь мне. Большое спасибо
1 ответ
Анимация ключевого кадра вносит ненужные сложности. Просто поверните метку вокруг центра на ту же продолжительность, что и анимация обводки слоя формы:
(Я извиняюсь, что моя анимация начинается снизу, а не сверху, но я не смотрел на ваш вопрос, когда писал код, и теперь мне лень его менять!)
Итак, как это сделать? Это три анимации, все с одинаковой продолжительностью:
Слой формы
strokeEnd
нравится твоя анимация."Рука", проходящая через центр круга, с меткой в качестве подслоя на одном конце (так что метка появляется в радиусе круга). Рука делает анимацию вращения вращения.
Метка выполняет вращение с преобразованием анимации в обратном направлении. Если бы он этого не сделал, он бы вращался вместе со своим суперслоем. (Подумайте о том, как работает колесо обозрения; ваше кресло находится на конце руки, но оно остается в вертикальном положении относительно земли.)
Это весь код анимации:
let anim = CABasicAnimation(keyPath: "transform.rotation.z")
anim.fromValue = 0
anim.toValue = 5
anim.duration = 10
self.arm.layer.add(anim, forKey:nil)
let anim2 = CABasicAnimation(keyPath: "transform.rotation.z")
anim2.fromValue = 0
anim2.toValue = -5
anim2.duration = 10
self.lab.layer.add(anim2, forKey:nil)
let anim3 = CABasicAnimation(keyPath: "strokeEnd")
anim3.fromValue = 0
anim3.toValue = 1
anim3.duration = 10
self.shape.add(anim3, forKey:nil)