Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rotate NSImageView at its Center to Make it Spin

Swift 4, macOS 10.13

I have read a variety of answers on SO and still can't get an NSImageView to spin at its center instead of one of its corners.

Right now, the image looks like this (video): http://d.pr/v/kwiuwS

Here is my code:

//`loader` is an NSImageView on my storyboard positioned with auto layout

loader.wantsLayer = true

let oldFrame = loader.layer?.frame
loader.layer?.anchorPoint = CGPoint(x: 0.5, y: 0.5)
loader.layer?.position = CGPoint(x: 0.5, y: 0.5)
loader.layer?.frame = oldFrame!

let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
rotateAnimation.fromValue = 0.0
rotateAnimation.toValue = CGFloat(-1 * .pi * 2.0)
rotateAnimation.duration = 2
rotateAnimation.repeatCount = .infinity

loader.layer?.add(rotateAnimation, forKey: nil)

Any ideas what I am still missing?

like image 520
Clifton Labrum Avatar asked Dec 11 '22 09:12

Clifton Labrum


1 Answers

I just created a simple demo which contains the handy setAnchorPoint extension for all views.

The main reason you see your rotation from a corner is that your anchor point is somehow reset to 0,0.

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

@IBOutlet weak var window: NSWindow!
var imageView: NSImageView!

func applicationDidFinishLaunching(_ aNotification: Notification) {
    // Insert code here to initialize your application

    // Create red NSImageView
    imageView = NSImageView(frame: NSRect(x: 100, y: 100, width: 100, height: 100))
    imageView.wantsLayer = true
    imageView.layer?.backgroundColor = NSColor.red.cgColor

    window.contentView?.addSubview(imageView)
}

func applicationWillTerminate(_ aNotification: Notification) {
    // Insert code here to tear down your application
}

func applicationDidBecomeActive(_ notification: Notification) {
    // Before animate, reset the anchor point
    imageView.setAnchorPoint(anchorPoint: CGPoint(x: 0.5, y: 0.5))
    // Start animation
    if imageView.layer?.animationKeys()?.count == 0 || imageView.layer?.animationKeys() == nil {
        let rotate = CABasicAnimation(keyPath: "transform.rotation")
        rotate.fromValue = 0
        rotate.toValue = CGFloat(-1 * .pi * 2.0)
        rotate.duration = 2
        rotate.repeatCount = Float.infinity

        imageView.layer?.add(rotate, forKey: "rotation")
    }
}
}

extension NSView {
    func setAnchorPoint(anchorPoint:CGPoint) {
        if let layer = self.layer {
            var newPoint = NSPoint(x: self.bounds.size.width * anchorPoint.x, y: self.bounds.size.height * anchorPoint.y)
            var oldPoint = NSPoint(x: self.bounds.size.width * layer.anchorPoint.x, y: self.bounds.size.height * layer.anchorPoint.y)

        newPoint = newPoint.applying(layer.affineTransform())
        oldPoint = oldPoint.applying(layer.affineTransform())

        var position = layer.position

        position.x -= oldPoint.x
        position.x += newPoint.x

        position.y -= oldPoint.y
        position.y += newPoint.y


        layer.anchorPoint = anchorPoint
        layer.position = position
    }
}
}

enter image description here

like image 112
brianLikeApple Avatar answered Feb 16 '23 08:02

brianLikeApple