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?
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
}
}
}