在Swift 3中,将UIImage顺时针旋转270度的正确方法是什么?

4
UIView.animate(withDuration:2.0, animations: {

         self.imageView.transform = CGAffineTransform(rotationAngle: (270 * CGFloat(2 * Double.pi)) / 360.0)
    })

这个动画是逆时针旋转的,我想让它顺时针旋转。

3个回答

9

要顺时针旋转270度...

UIView.animate(withDuration:2.0, animations: {
            self.sampleView.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi))
            self.sampleView.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi * 3 / 2))
        })

核心动画将始终采用最短路径使旋转起作用。因此,如果您的对象是直的,并且您将其旋转90度(弧度:pi/2),它将顺时针旋转。如果您的对象是直的,并且您将其旋转270度(弧度:pi + pi/2 = 3pi/2),它将逆时针旋转,因为这是最小可能的动画。

所以我们首先需要旋转π弧度(从0到π,0到180),然后再旋转π/2弧度(π到3π/2,180到270)来执行完整的旋转。
注意:

  • 要旋转大于180度的角度,您需要执行两个变换,一个用于前180度,另一个用于其余部分。
  • 要旋转大于360度(如一圈半)的角度,您需要执行三个变换。
  • 要旋转奇数角度,比如195度,先旋转180度,然后再旋转15度。
  • 在执行旋转时,您需要将度数转换为弧度。

我测试了一下,它顺时针旋转了90度。 您想要多少角度的旋转以及旋转方向是哪个? - NSAdi
我想要一个完整圆形顺时针旋转270度。 - Zubin Gala
谢谢NSAdi,这个方法很有效。如果我想旋转到195度或其他任何角度怎么办? - Zubin Gala
1
Swift使用弧度作为旋转测量单位。您应该计算所需旋转角度的弧度等效值,并将该值作为参数提供。请搜索“度到弧度”。 - mert dökümcü
我刚刚重新写了我的回答。希望现在它能够解释清楚你需要做什么以及为什么这样做。 - NSAdi

4
在iOS中,坐标系被翻转了。所以当你增加度数时,顺时针方向是对的。这意味着经过270°会给你一个角度,相当于标准坐标系中的90°。记住这一点并相应地提供所需的角度。
考虑以下的方法。
1)角度的便捷扩展
postfix operator °

protocol IntegerInitializable: ExpressibleByIntegerLiteral {
    init (_: Int)
}

extension Int: IntegerInitializable {
    postfix public static func °(lhs: Int) -> CGFloat {
        return CGFloat(lhs) * .pi / 180
    }
}

extension CGFloat: IntegerInitializable {
    postfix public static func °(lhs: CGFloat) -> CGFloat {
        return lhs * .pi / 180
    }
}

2) 使用 CABasicAnimation 实现任意角度旋转:

extension UIView {
    func rotateWithAnimation(angle: CGFloat, duration: CGFloat? = nil) {
        let pathAnimation = CABasicAnimation(keyPath: "transform.rotation")
        pathAnimation.duration = CFTimeInterval(duration ?? 2.0)
        pathAnimation.fromValue = 0
        pathAnimation.toValue = angle
        pathAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        self.transform = transform.rotated(by: angle)
        self.layer.add(pathAnimation, forKey: "transform.rotation")
    }
}

使用方法:

override func viewDidAppear(_ animated: Bool) {
    // clockwise
    myView.rotateWithAnimation(angle: 90°)

    // counter-clockwise
    myView.rotateWithAnimation(angle: -270°) 

}

传递负值将逆时针旋转。

可爱的扩展和方便实用。<3 - Zubin Gala
isRemovedOnCompletion = falsefillMode = kCAFillModeForwards相结合并不是一种使动画“固定”的好方法,主要是因为它会使图层属性与其在屏幕上显示的方式之间的差异随时间而持续存在,这可能会导致错误。更强大、最佳的做法是在添加动画前更新图层属性,然后让动画在完成时自行删除。 - David Rönnqvist
话虽如此,我认为在大多数情况下这仍然是一种可以被视为适当的方式,因为这正是这些标志旨在设计的。当您将结果值分配给属性时,即使更安全,也更像是一种黑客技巧,因为在应用动画和应用属性之间存在轻微(尽管无法捕获)的瞬间,可能会导致类似的UI问题。 - Hexfire
因此,通过设置图层的属性,UI也会被欺骗,因为动画会降至“fromValue”,这与所设置的值不同。但是一旦启动,将不会出现任何问题,因为动画完成了。 - Hexfire

2

解释

旋转的问题在于它会找到完成旋转的最短路径。 因此,当您的视图在开始时旋转了0度时,旋转该视图至270度的最短路径是将视图旋转-90度。

您需要结合两个动画来完成这个过程。

第一个: 将视图旋转180 + 1度 (加1告诉动画您想顺时针旋转-更短的路径)

第二个: 将视图旋转90度

在代码中:

假设您有一个名为rotateView的UIView。

@objc func rotate() {
        if rotateView.transform == .identity {
            UIView.animate(withDuration: 0.5) {
                self.rotateView.transform = CGAffineTransform(rotationAngle: (CGFloat.pi) + 1)
            }

            UIView.animate(withDuration: 0.5, delay: 0.25, options:[], animations: {
                self.rotateView.transform = CGAffineTransform(rotationAngle: (CGFloat.pi / 2))
            }, completion: nil)

        } else {
            UIView.animate(withDuration: 0.5, animations: {
                self.rotateView.transform = .identity
            })
        }
    }

.identity检查您的rotateView是否处于其“起始位置”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接