动态改变NSWindow的isMovableByWindowBackground和isMovable

MAH*_*MAH 1 cocoa

我一直在努力解决这个非常令人沮丧的问题,希望有人能提供帮助。我正在尝试创建一个具有多个视图的 NSWindow。视图可以相互重叠。这些就是要求。

  • 如下图所示,蓝色的 NSView 是可以移动窗口的。
  • 黄色的 NSView 无法移动窗口。这是另一个 NSView 实例,位于蓝色 NSView 下方。
  • 该运动需要感觉像任何其他窗口运动一样。
  • 将窗口一直拖到顶部之类的操作应该激活 Expose(Sierra 和 High Sierra)。

在此输入图像描述

第一次尝试

我已经通过尝试以下方法进行了尝试。不幸的是,这根本行不通。

在 NSWindow 中

override func awakeFromNib() {
    self.refreshElements()
    self.titlebarAppearsTransparent = true
    self.isMovableByWindowBackground = true
}
Run Code Online (Sandbox Code Playgroud)

在我的自定义视图中

class Blue: NSView {
    public override var mouseDownCanMoveWindow: Bool { return true }
}

class Yellow: NSView {
    public override var mouseDownCanMoveWindow: Bool { return false }
}
Run Code Online (Sandbox Code Playgroud)

第二次尝试

然后我尝试在 Blue 中实现mouseDown mouseDragged和。mouseUp我会计算鼠标self.setFrame(frameRect:display:animate:)在窗口上的移动。这很有效,因为我可以控制移动窗口,但它有几个问题。无论如何,窗口的移动速度总是较慢。我认为即使我将animate属性设置为 false,它也会有动画。而且它不像其他窗口那样激活 Expose。


第三次尝试

这是我在一个重大问题上最接近我想要的行为。初始 mouseDown 未注册。所以你不能点击蓝色视图并拖动和移动窗口。您可以使用 mouseDown、mouseUp,然后再次使用 mouseDown,以便通过拖动来移动窗口。

public class MyWindow: NSWindow {

    @IBOutlet var blue: NSView!
    @IBOutlet var yellow: NSView!

    public override func awakeFromNib() {
        self.titlebarAppearsTransparent = true
        self.isMovable = false
        self.isMovableByWindowBackground = true
    }

    public override func mouseDown(with event: NSEvent) {
        let point = event.locationInWindow

        let move = NSPointInRect(point, self.blue.frame)
        self.isMovableByWindowBackground = move
        self.isMovable = move

        super.mouseDown(with: event)
    }
    public override func mouseDragged(with event: NSEvent) {
        super.mouseDragged(with: event)
    }

}
Run Code Online (Sandbox Code Playgroud)

我首选的方法是方法 3。它是最干净的代码,除了必须单击然后再次单击才能正常工作的异常行为之外,其他一切都很完美。我的问题是,在动态设置为允许移动后,如何强制初始单击也注册到窗口?

Ken*_*ses 5

从 macOS 10.11 开始,就有了用于此目的的NSWindow方法。performDrag(with:)它启动窗口拖动,就像用户单击并拖动标题栏时所做的那样。您的蓝色视图可以简单地在其覆盖中调用它mouseDown()

问题mouseDownCanMoveWindow是它只是将问题传递给超级视图。除非直到窗口内容视图的所有祖先视图都返回 true,否则这并不重要。