gpt4 book ai didi

swift - 如何更新 NSView 图层位置和 anchor 以与鼠标事件的 NSView 框架同时进行转换

转载 作者:行者123 更新时间:2023-11-28 05:58:03 26 4
gpt4 key购买 nike

我目前正在尝试实现一些自定义 NSView,这些 NSView 将通过 macOS 应用程序中的某些事件进行动画处理。这些控件沿着您会在 AudioUnit 插件中找到的 slider 线。

关于动画的问题在this question中已经得到解答。 .

我不确定的是如何更改 View 的 CALayer 位置和 anchor 以进行旋转并为鼠标事件更新其框架。

作为一个基本示例,我希望通过创建一个 NSView 并设置它的背景颜色来绘制一个正方形。然后我想在 mouseDown 事件上为 View 的旋转设置动画,就像前面的链接一样。

通过以下设置, View 被移动到窗口的中心,它的 anchor 被改变,以便 View 围绕它而不是围绕 window.contentView! 的原点旋转。但是,移动 view.layer.position 并设置 view.layer!.anchorPoint = CGPoint(x: 0.5,y: 0.5) 也不会移动框架将检测事件。

@IBOutlet weak var window: NSWindow!

func applicationDidFinishLaunching(_ aNotification: Notification)
{
let view = customView(frame: NSRect(x: 0, y: 0, width: 50, height: 50))
window.contentView!.wantsLayer = true
view.wantsLayer = true
view.layer?.backgroundColor = NSColor.blue.cgColor
window.contentView?.addSubview(view)

let containerFrame = window.contentView!.frame
let center = CGPoint(x: containerFrame.midX, y: containerFrame.midY)
view.layer?.position = center
view.layer?.anchorPoint = CGPoint(x: 0.5,y: 0.5)
}

本例中的 customView 只是一个 NSView,带有在 mouseDown 上执行的上一个链接的旋转动画

override func mouseDown(with event: NSEvent)
{
let timeToRotate = 1
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
rotateAnimation.fromValue = 0.0
rotateAnimation.toValue = angle
rotateAnimation.duration = timeToRotate
rotateAnimation.repeatCount = .infinity
self.layer?.add(rotateAnimation, forKey: nil)
}

通过设置 view.frame = view.layer.frame 移动框架会导致 View 围绕其中一个角旋转。所以,我改变了 view.setFrameOrigin()

@IBOutlet weak var window: NSWindow!

func applicationDidFinishLaunching(_ aNotification: Notification)
{
let view = customView(frame: NSRect(x: 0, y: 0, width: 50, height: 50))
window.contentView!.wantsLayer = true
view.wantsLayer = true
view.layer?.backgroundColor = NSColor.blue.cgColor
window.contentView?.addSubview(view)

let containerFrame = window.contentView!.frame
let center = CGPoint(x: containerFrame.midX, y: containerFrame.midY)
let offsetFrameOrigin = CGPoint(x: center.x - view.bounds.width/2,
y: center.y - view.bounds.height/2)
view.setFrameOrigin(offsetFrameOrigin)
view.layer?.position = center
view.layer?.anchorPoint = CGPoint(x: 0.5,y: 0.5)
}

将 view.frame 原点设置为中心的偏移量可以实现我想要的效果,但我忍不住觉得这有点“hacky”,我可能以错误的方式接近它。特别是因为对 view.layerview.frame 的任何进一步更改将导致动画不正确或在绘制内容之外检测到事件。

如何更改 NSView.layer 使其在设置 NSView.frame 的同时围绕其中心旋转,以便在正确的区域检测到鼠标事件?

此外,改变 NSView.layer.anchorPoint 是否是设置它围绕其中心旋转的正确方法?

最佳答案

我想我的处境和你差不多。幸运的是,我偶然发现了一个 gist that extends NSView with a setAnchorPoint function这对我有用(使图层的 anchor 与主框架保持同步)。

有一个 fork for that gist for Swift 4 .这是代码本身:

extension NSView
{
func setAnchorPoint (anchorPoint:CGPoint)
{
if let layer = self.layer
{
var newPoint = CGPoint(x: self.bounds.size.width * anchorPoint.x, y: self.bounds.size.height * anchorPoint.y)
var oldPoint = CGPoint(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.position = position
layer.anchorPoint = anchorPoint
}
}
}

然后您可以像这样直接在 NSView(即不是它的层)使用它:

func applicationDidFinishLaunching(_ aNotification: Notification)
{
// ... //
let view = customView(frame: NSRect(x: 0, y: 0, width: 50, height: 50))
view.wantsLayer = true
view.setAnchorPoint(anchorPoint: CGPoint(x: 0.5, y: 0.5))
// ... //
}

关于swift - 如何更新 NSView 图层位置和 anchor 以与鼠标事件的 NSView 框架同时进行转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50787694/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com