Rotate a view for 360 degrees indefinitely in Swift?

后端 未结 10 1164
闹比i
闹比i 2020-12-05 13:06

I want to rotate an image view for 360 degrees indefinitely.

UIView.animate(withDuration: 2, delay: 0, options: [.repeat], animations: {
    self.view.transf         


        
相关标签:
10条回答
  • 2020-12-05 13:53

    Updated for Swift 3: I made an extension to UIView and included the following function within:

    func rotate(fromValue: CGFloat, toValue: CGFloat, duration: CFTimeInterval = 1.0, completionDelegate: Any? = nil) {
    
    let rotateAnimation = CABasicAnimation(keyPath: >"transform.rotation")
    rotateAnimation.fromValue = fromValue
    rotateAnimation.toValue = toValue
    rotateAnimation.duration = duration
    
    if let delegate: Any = completionDelegate {
    rotateAnimation.delegate = delegate as? CAAnimationDelegate
    }
    self.layer.add(rotateAnimation, forKey: nil)
    
    }
    

    You can then call the function via (on a UIView I made into a button for example) :

    monitorButton.rotate(fromValue: 0.0, toValue: CGFloat(M_PI * 2), completionDelegate: self)
    

    Hope this helps!

    0 讨论(0)
  • 2020-12-05 13:53

    I think what you really want here is to use a CADisplayLink. Reason being that this would be indefinitely smooth versus using completion blocks which may cause slight hiccups and are not as easily cancelable. See the following solution:

    var displayLink : CADisplayLink?
    var targetView = UIView()
    
    func beginRotation () {
    
        // Setup display link
        self.displayLink = CADisplayLink(target: self, selector: #selector(onFrameInterval(displayLink:)))
        self.displayLink?.preferredFramesPerSecond = 60
        self.displayLink?.add(to: .current, forMode: RunLoop.Mode.default)
    }
    
    func stopRotation () {
    
        // Invalidate display link
        self.displayLink?.invalidate()
        self.displayLink = nil
    }
    
    // Called everytime the display is refreshed
    @objc func onFrameInterval (displayLink: CADisplayLink) {
    
        // Get frames per second
        let framesPerSecond = Double(displayLink.preferredFramesPerSecond)
    
        // Based on fps, calculate how much target view should spin each interval
        let rotationsPerSecond = Double(3)
        let anglePerSecond = rotationsPerSecond * (2 * Double.pi)
        let anglePerInterval = CGFloat(anglePerSecond / framesPerSecond)
    
        // Rotate target view to match the current angle of the interval
        self.targetView.layer.transform = CATransform3DRotate(self.targetView.layer.transform, anglePerInterval, 0, 0, 1)
    
    }
    
    0 讨论(0)
  • 2020-12-05 13:55

    Swift 3.0

    let imgViewRing = UIImageView(image: UIImage(named: "apple"))
    imgViewRing.frame = CGRect(x: 0, y: 0, width: UIImage(named: "apple")!.size.width, height: UIImage(named: "apple")!.size.height)
    imgViewRing.center = CGPoint(x: self.view.frame.size.width/2.0, y: self.view.frame.size.height/2.0)
    rotateAnimation(imageView: imgViewRing)
    self.view.addSubview(imgViewRing)
    

    This is the animation logic

    func rotateAnimation(imageView:UIImageView,duration: CFTimeInterval = 2.0) {
            let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
            rotateAnimation.fromValue = 0.0
            rotateAnimation.toValue = CGFloat(.pi * 2.0)
            rotateAnimation.duration = duration
            rotateAnimation.repeatCount = .greatestFiniteMagnitude
    
            imageView.layer.add(rotateAnimation, forKey: nil)
        }
    

    You can check output in this link

    0 讨论(0)
  • 2020-12-05 13:55

    Avoiding the completion closure with recursive calls!

    Bit late to this party, but using UIView keyFrame animation & varying stages of rotation for each keyFrame, plus setting the animation curve works nicely. Here's an UIView class function -

    class func rotate360(_ view: UIView, duration: TimeInterval, repeating: Bool = true) {
    
        let transform1 = CGAffineTransform(rotationAngle: .pi * 0.75)
        let transform2 = CGAffineTransform(rotationAngle: .pi * 1.5)
    
        let animationOptions: UInt
        if repeating {
            animationOptions = UIView.AnimationOptions.curveLinear.rawValue | UIView.AnimationOptions.repeat.rawValue
        } else {
            animationOptions = UIView.AnimationOptions.curveLinear.rawValue
        }
    
        let keyFrameAnimationOptions = UIView.KeyframeAnimationOptions(rawValue: animationOptions)
    
        UIView.animateKeyframes(withDuration: duration, delay: 0, options: [keyFrameAnimationOptions, .calculationModeLinear], animations: {
            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.375) {
                view.transform = transform1
            }
            UIView.addKeyframe(withRelativeStartTime: 0.375, relativeDuration: 0.375) {
                view.transform = transform2
            }
            UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25) {
                view.transform = .identity
            }
        }, completion: nil)
    }
    

    Looks pretty gnarly, with the weird rotation angles, but as the op & others have found, you can't just tell it to rotate 360

    0 讨论(0)
提交回复
热议问题