On macOS Sierra the following code worked as expected, showing an animated image, rotating from the "centre" of the view.
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
statusItem.button?.isEnabled = true
let image = NSImage(named:"statusItem")!
image.isTemplate = true
statusItem.button?.image = image
statusItem.button?.wantsLayer = true
let basicAnimation = CABasicAnimation(keyPath:"transform.rotation")
basicAnimation.fromValue = 2.0 * .pi
basicAnimation.toValue = 0.0
basicAnimation.duration = 1.0
basicAnimation.repeatCount = Float.infinity
statusItem.button?.layer?.add(basicAnimation, forKey: "spinAnimation")
Output
On **macOS High Sierra** however, there is a "background" and the animation happens on the bottom left corner at a wide angle.
Output
AFAICS, customisation of a `NSStatusItem` is pretty limited so decided to jump on Core Animation and layers.
Using the following code
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
statusItem.button?.isEnabled = true
let layer = CALayer()
statusItem.button?.layer = layer
statusItem.button?.wantsLayer = true
let image = NSImage(named:NSImage.Name(rawValue: "statusItem"))
image?.isTemplate = true
statusItem.button?.layer?.contents = image
let basicAnimation = CABasicAnimation(keyPath:"transform.rotation")
basicAnimation.fromValue = 2.0 * .pi
basicAnimation.toValue = 0.0
basicAnimation.duration = 1.0
basicAnimation.repeatCount = Float.infinity
statusItem.button?.layer?.add(basicAnimation, forKey: "spinAnimation")
statusItem.button?.layer?.anchorPoint = CGPoint(x: 0.5, y: 0.5)
Still leaves the background while the image position initially is at the centre before jumping at the bottom left corner to rotate.
Output
Sample Project
References
Update
Have managed to make the position of the image centred by implementing the `func display(_ layer: CALayer)` method in a `CALayerDelegate`.
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
statusItem.button?.isEnabled = true
let layer = CALayer()
layer.delegate = self
statusItem.button?.layer = layer
statusItem.button?.wantsLayer = true
let basicAnimation = CABasicAnimation(keyPath:"transform.rotation")
basicAnimation.fromValue = 2.0 * .pi
basicAnimation.toValue = 0.0
basicAnimation.duration = 1.0
basicAnimation.repeatCount = Float.infinity
statusItem.button?.layer?.add(basicAnimation, forKey: "spinAnimation")
statusItem.button?.layerContentsRedrawPolicy = .onSetNeedsDisplay
statusItem.button?.layer?.setNeedsDisplay()
CALayerDelegate
func display(_ layer: CALayer) {
let frame = layer.frame
layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
layer.frame = frame
layer.contentsScale = 2.0
layer.contentsGravity = "aspectFit"
let image = NSImage(named:"statusItem")!
image.isTemplate = true
layer.contents = image
}
Still the background remains.
For what is worth, setting the `NSStatusItem. NSStatusBarButton.image` property with the template image displays the image correctly, however there is no way to then animate it.
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
statusItem.button?.isEnabled = true
let image = NSImage(named:"statusItem")!
image.isTemplate = true
statusItem.button?.image = image
Tried to debug the UI Hierarchy and if I understand this correctly, when setting the NSImage to the `contents` property of the layer, the image is not drawn as a template.
In both cases, the [`backgroundcolor`][11] and [`NSImageRep`][12] are
Generic Gray Gamma 2.2 Profile colorspace 0 0
and
NSCGImageRep 0x6000000850a0 Size={16, 16} ColorSpace=sRGB IEC61966-2.1 colorspace BPS=0 Pixels=32x32 Alpha=NO
respectively.