ios - 如何避免旋转动画在 2π 边界跳跃?

标签 ios core-animation caanimation

我正在使用 CAKeyframeAnimation 沿 CGPath 为箭头制作动画。箭头跟随路径,除非 atan2 的输出从 0 翻转到 2π,反之亦然。在这种情况下,箭头会在继续之前进行完整的 360° 旋转。

有没有什么方法可以计算我的 CAKeyframeAnimation 的值,以便箭头始终旋转最小量以到达它要去的地方?

        let turnAnimation = CAKeyframeAnimation(keyPath: "transform.rotation")
        turnAnimation.duration = 5

        var values = [CGFloat]()
        for i in 0..<points.count - 1 {

            let point1 = points[i]
            let point2 = points[i + 1]
            let delta = point2 - point1
            let value = atan2(delta.y, delta.x)

            values.append(value)
        }

        turnAnimation.values = values
        turnAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        turnAnimation.repeatCount = Float.greatestFiniteMagnitude
        arrowPointLayer.transform = CATransform3DMakeRotation(values.first!, 0, 0, 1)
        arrowPointLayer.add(turnAnimation, forKey: "rotateArrow")

编辑:根据答案进行了更新,但仍然无法正常工作:

let turnAnimation = CAKeyframeAnimation(keyPath: "transform.rotation")
        turnAnimation.duration = 5

        var rawValues = [CGFloat]()
        var values = [CGFloat]()
        for i in 0..<points.count - 1 {

            let point1 = points[i]
            let point2 = points[i + 1]
            let delta = point2 - point1
            let rawValue = atan2(delta.y, delta.x)

            var value: CGFloat

            if i == 0 {
                value = 0 // we will apply this value from rawValues
            } else {
                let lastValue = rawValues.last!
                value = rawValue - lastValue
            }

            if value < 0 {
                value = .pi * 2 + value
            }

            rawValues.append(rawValue)

            values.append(value)
        }

        for (i, p) in values.enumerated() {
            print("\(rawValues[i]): \(p)")
        }

        turnAnimation.values = values
        turnAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        turnAnimation.repeatCount = Float.greatestFiniteMagnitude
        turnAnimation.isAdditive = true

        arrowPointLayer.transform = CATransform3DMakeRotation(rawValues.first!, 0, 0, 1)
        arrowPointLayer.add(turnAnimation, forKey: "rotateArrow")

最佳答案

与其将 values 设为绝对旋转值列表,不如将其设为旋转差异 列表并将动画的 isAdditive 设置为 。这样,就可以告诉箭头向哪个方向转动以及转动多少。

我这样测试(在我的测试中,v 只是我界面中的一些 View ):

let turnAnimation = CAKeyframeAnimation(keyPath: "transform.rotation")
turnAnimation.duration = 5
let values : [CGFloat] = [0,2,-1,2,-1,3,-3]
turnAnimation.values = values
turnAnimation.timingFunction = 
    CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
turnAnimation.isAdditive = true
self.v.layer.add(turnAnimation, forKey: "rotateArrow")

View 的行为完全符合我的预期。

关于ios - 如何避免旋转动画在 2π 边界跳跃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40107884/

相关文章:

ios - UICollectionViewCell 响应多个手势识别器

iphone - CAReplicatorLayer 随机位置

cocoa - 动画DidStop :finished: not called

ios - 延迟 CATransition 的开始

ios - 无法在 Objective-C 中使用 Swift 生成的共享框架

ios - 未声明委托(delegate)?

ios - SoundCloud 轨道在 iPhone 中播放时间过长

iphone - 删除 UIButton 层上的 CAShapeLayer 掩码,以便动画 UIButton 大小更改被取消掩码

ios - 如何从 SVGkit 获取 CGPathRef?或者更好的解决方案来为 CAKeyframeAnimation 创建 CGPaths?

ios - UIView的addMotionEffect : loses it's effect when on UICollectionViewCell