在其中心旋转 NSImageView 使其旋转
Rotate NSImageView at its Center to Make it Spin
Swift 4、macOS 10.13
我已经阅读了关于 SO 的各种答案,但仍然无法让 NSImageView
在其中心而不是其中一个角处旋转。
现在,图像看起来像这样(视频):http://d.pr/v/kwiuwS
这是我的代码:
//`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)
知道我还缺少什么吗?
这是布局过程将视图图层重置为默认属性的结果。例如,如果您检查图层的 anchorPoint
,您会发现它可能已重置为 0, 0
。
如果您在视图控制器中,一个简单的解决方案是在 viewDidLayout()
中不断设置所需的图层属性。基本上是在每次布局过程中执行您在初始设置中执行的框架、锚点和位置舞蹈。如果您子类化 NSImageView
您可能会在该视图中包含该逻辑,这比将该逻辑放在包含视图控制器中要好得多。
可能有更好的解决方案,可以覆盖支持层或滚动您自己的使用 updateLayer
的 NSView 子类,但我必须在那里进行试验才能给出明确的答案。
我刚刚创建了一个简单的演示,其中包含适用于所有视图的便捷 setAnchorPoint
扩展。
您从角落看到旋转的主要原因是您的锚点以某种方式重置为 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
}
}
}
正如我自己在这个问题上多次想知道的那样,这是我自己旋转任何 NSView 的简单方法。我post也把它当做一个自我提醒。如果需要,可以在类别中定义它。
这是简单的旋转,不是连续动画。应应用于 wantsLayer = YES 的 NSView 实例。
- (void)rotateByNumber:(NSNumber*)angle {
self.layer.position = CGPointMake(NSMidX(self.frame), NSMidY(self.frame));
self.layer.anchorPoint = CGPointMake(.5, .5);
self.layer.affineTransform = CGAffineTransformMakeRotation(angle.floatValue);
}
Swift 4、macOS 10.13
我已经阅读了关于 SO 的各种答案,但仍然无法让 NSImageView
在其中心而不是其中一个角处旋转。
现在,图像看起来像这样(视频):http://d.pr/v/kwiuwS
这是我的代码:
//`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)
知道我还缺少什么吗?
这是布局过程将视图图层重置为默认属性的结果。例如,如果您检查图层的 anchorPoint
,您会发现它可能已重置为 0, 0
。
如果您在视图控制器中,一个简单的解决方案是在 viewDidLayout()
中不断设置所需的图层属性。基本上是在每次布局过程中执行您在初始设置中执行的框架、锚点和位置舞蹈。如果您子类化 NSImageView
您可能会在该视图中包含该逻辑,这比将该逻辑放在包含视图控制器中要好得多。
可能有更好的解决方案,可以覆盖支持层或滚动您自己的使用 updateLayer
的 NSView 子类,但我必须在那里进行试验才能给出明确的答案。
我刚刚创建了一个简单的演示,其中包含适用于所有视图的便捷 setAnchorPoint
扩展。
您从角落看到旋转的主要原因是您的锚点以某种方式重置为 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
}
}
}
正如我自己在这个问题上多次想知道的那样,这是我自己旋转任何 NSView 的简单方法。我post也把它当做一个自我提醒。如果需要,可以在类别中定义它。
这是简单的旋转,不是连续动画。应应用于 wantsLayer = YES 的 NSView 实例。
- (void)rotateByNumber:(NSNumber*)angle {
self.layer.position = CGPointMake(NSMidX(self.frame), NSMidY(self.frame));
self.layer.anchorPoint = CGPointMake(.5, .5);
self.layer.affineTransform = CGAffineTransformMakeRotation(angle.floatValue);
}