如何防止 NSImageView 在其父 NSToolbar 为 hidden/shown 时丢失动画?
How to prevent an NSImageView from loosing an animation when its parent NSToolbar is hidden/shown?
Xcode: 9.2.
macOS 目标:10.13
当父 NSToolbar 被隐藏然后随后显示时,NSImageView 似乎会丢失添加到其图层的所有动画。
有没有办法指示 AppKit 成为手 off/restore 动画的状态?
示例代码
class WindowController: NSWindowController, CALayerDelegate {
static let spinAnimation: CAAnimation = {
let basicAnimation = CABasicAnimation(keyPath:"transform.rotation")
basicAnimation.fromValue = 2.0 * .pi
basicAnimation.toValue = 0.0
basicAnimation.duration = 1.0
basicAnimation.repeatCount = Float.infinity
return basicAnimation
}()
@IBOutlet weak var imageView: NSImageView! {
didSet{
let layer = CALayer()
layer.contentsScale = 2.0
layer.contentsGravity = "aspectFit"
layer.contents = #imageLiteral(resourceName: "windmill")
imageView.layer = layer
imageView.wantsLayer = true
imageView.layerContentsRedrawPolicy = .onSetNeedsDisplay
imageView.layer?.delegate = self
imageView.needsDisplay = true
}
}
func display(_ layer: CALayer) {
let frame = layer.frame
layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
layer.frame = frame
}
override func windowDidLoad() {
super.windowDidLoad()
let key = "spinAnimation"
self.imageView.layer?.add(WindowController.spinAnimation, forKey: key)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(5)) {
self.imageView.layer?.removeAnimation(forKey: key)
}
}
}
通常,当动画层从 on-screen 层树中移除时,动画被视为“完成”。默认情况下,动画完成后会从其图层中移除。 AppKit 从 window 中删除了工具栏视图(以及它的所有子视图及其层),因此动画被认为已完成并从其层中删除。
要保持动画安装,您可以将动画的 isRemovedOnCompletion
设置为 false
。
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
@IBOutlet var customItem: NSToolbarItem!
func applicationDidFinishLaunching(_ aNotification: Notification) {
let view = customItem.view!
view.wantsLayer = true
let layer = view.layer!
let frame = layer.frame
layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
layer.frame = frame
let animation = CABasicAnimation(keyPath: "transform.rotation")
animation.fromValue = CGFloat(0)
animation.toValue = 2 * CGFloat.pi
animation.duration = 1
animation.repeatCount = .infinity
animation.isRemovedOnCompletion = false
layer.add(animation, forKey: animation.keyPath)
}
}
结果:
Xcode: 9.2.
macOS 目标:10.13
当父 NSToolbar 被隐藏然后随后显示时,NSImageView 似乎会丢失添加到其图层的所有动画。
有没有办法指示 AppKit 成为手 off/restore 动画的状态?
示例代码
class WindowController: NSWindowController, CALayerDelegate {
static let spinAnimation: CAAnimation = {
let basicAnimation = CABasicAnimation(keyPath:"transform.rotation")
basicAnimation.fromValue = 2.0 * .pi
basicAnimation.toValue = 0.0
basicAnimation.duration = 1.0
basicAnimation.repeatCount = Float.infinity
return basicAnimation
}()
@IBOutlet weak var imageView: NSImageView! {
didSet{
let layer = CALayer()
layer.contentsScale = 2.0
layer.contentsGravity = "aspectFit"
layer.contents = #imageLiteral(resourceName: "windmill")
imageView.layer = layer
imageView.wantsLayer = true
imageView.layerContentsRedrawPolicy = .onSetNeedsDisplay
imageView.layer?.delegate = self
imageView.needsDisplay = true
}
}
func display(_ layer: CALayer) {
let frame = layer.frame
layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
layer.frame = frame
}
override func windowDidLoad() {
super.windowDidLoad()
let key = "spinAnimation"
self.imageView.layer?.add(WindowController.spinAnimation, forKey: key)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(5)) {
self.imageView.layer?.removeAnimation(forKey: key)
}
}
}
通常,当动画层从 on-screen 层树中移除时,动画被视为“完成”。默认情况下,动画完成后会从其图层中移除。 AppKit 从 window 中删除了工具栏视图(以及它的所有子视图及其层),因此动画被认为已完成并从其层中删除。
要保持动画安装,您可以将动画的 isRemovedOnCompletion
设置为 false
。
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
@IBOutlet var customItem: NSToolbarItem!
func applicationDidFinishLaunching(_ aNotification: Notification) {
let view = customItem.view!
view.wantsLayer = true
let layer = view.layer!
let frame = layer.frame
layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
layer.frame = frame
let animation = CABasicAnimation(keyPath: "transform.rotation")
animation.fromValue = CGFloat(0)
animation.toValue = 2 * CGFloat.pi
animation.duration = 1
animation.repeatCount = .infinity
animation.isRemovedOnCompletion = false
layer.add(animation, forKey: animation.keyPath)
}
}
结果: