通过拖动NSView移动NSWindow

时间:2015-06-21 10:52:00

标签: macos swift cocoa nsview nswindow

我有一个NSWindow,我在上面申请:

window.styleMask = window.styleMask | NSFullSizeContentViewWindowMask
window.titleVisibility = NSWindowTitleVisibility.Hidden;
window.titlebarAppearsTransparent = true;

然后我在标题栏后面添加一个NSView来模拟一个更大的。 现在它看起来像这样: Current window

我希望能够通过拖动浅蓝色视图来移动窗口。我已经尝试使用此代码继承NSView并始终为mouseDownCanMoveWindow返回true:

class LSViewD: NSView {
    override var mouseDownCanMoveWindow:Bool {
        get {
            return true
        }
    }
}

这没有用。 经过一些谷歌搜索后,我在GitHub上发现了这个INAppStoreWindow。但它不支持OS X版本超过10.9,所以对我来说它完全没用。

EDIT1

这是它在Interface Builder中的外观。 Interface Builder

如何通过拖动此NSView来移动窗口?

6 个答案:

答案 0 :(得分:11)

尝试将窗口的movableByWindowBackground属性设置为true。

答案 1 :(得分:1)

有两种方法可以做到这一点。第一个是将NSTexturedBackgroundWindowMask以及窗口背景颜色设置为您的视图之一。这应该有用。

否则,您可以查看此Sample Code

答案 2 :(得分:0)

我设法解决了我的问题,我真的不知道如何,但这里有一些截图。

enter image description here enter image description here enter image description here

在我编辑窗口属性的AppDelegate文件中,我添加了一个我的contentView的IBOutlet。这个IBOutlet是NSView的子类,我在其中覆盖变量mouseDownCanMoveWindow,因此它总是返回false。

我之前只在一个文件中尝试过这个,但它没有用。然而,这解决了这个问题。

感谢Ken ThomasesMax引导我走向正确的方向。

答案 3 :(得分:0)

Swift3.0版本

override func viewDidAppear() {

    //for hide the TitleBar
    self.view.window?.styleMask = .borderless
    self.view.window?.titlebarAppearsTransparent = true
    self.view.window?.titleVisibility = .hidden

    //for Window movable with NSView
    self.view.window?.isMovableByWindowBackground = true

}

答案 4 :(得分:0)

迅速3:

我需要这个,但是很动态。它有点长,但值得(恕我直言)。

因此,我决定在按下命令键时仅启用 。这是通过在委托中注册本地密钥处理程序来实现的:

// MARK:- Local key monitor
var localKeyDownMonitor : Any? = nil
var commandKeyDown : Bool = false {
    didSet {
        let notif = Notification(name: Notification.Name(rawValue: "commandKeyDown"),
                                 object: NSNumber(booleanLiteral: commandKeyDown))
        NotificationCenter.default.post(notif)
    }
}

func keyDownMonitor(event: NSEvent) -> Bool {
    switch event.modifierFlags.intersection(.deviceIndependentFlagsMask) {

    case [.command]:
        self.commandKeyDown = true
        return true

    default:
        self.commandKeyDown = false
        return false
    }
}

在委托启动中启用的

func applicationDidFinishLaunching(_ aNotification: Notification) {     
    //  Watch local keys for window movenment, etc.
    localKeyDownMonitor = NSEvent.addLocalMonitorForEvents(matching: NSEventMask.flagsChanged) { (event) -> NSEvent? in
        return self.keyDownMonitor(event: event) ? nil : event
    }
}

及其删除

func applicationWillTerminate(_ aNotification: Notification) {  
    //  Forget key down monitoring
    NSEvent.removeMonitor(localKeyDownMonitor!)
}

请注意,当按下按键处理程序更改commandKeyDown值时。 didset {}捕获了此值更改以发布通知。您希望移动其窗口的任何视图都注册了此通知-即在视图委托中

override func viewDidLoad() {
    super.viewDidLoad()

    //  Watch command key changes
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(ViewController.commandKeyDown(_:)),
        name: NSNotification.Name(rawValue: "commandKeyDown"),
        object: nil)
}

,并在viewWillDisappear()(委托)或窗口控制器windowShouldClose()时丢弃;添加

    <your-view>.removeObserver(self, forKeyPath: "commandKeyDown")

所以序列是这样的:

  1. 按键/释放
  2. 处理程序称为
  3. 通知已发布

视图的isMovableByWindowBackground属性通过通知更改-放置在视图控制器/委托中或您注册观察者的位置。

internal func commandKeyDown(_ notification : Notification) {
    let commandKeyDown : NSNumber = notification.object as! NSNumber
    if let window = self.view.window {
        window.isMovableByWindowBackground = commandKeyDown.boolValue
        Swift.print(String(format: "command %@", commandKeyDown.boolValue ? "v" : "^"))
    }
}

高兴时删除跟踪器输出。在github上的SimpleViewer中查看它的运行情况。

答案 5 :(得分:0)

这里没有答案对我有用。它们要么根本不起作用,要么使整个窗口处于可拖动状态(请注意,OP并没有要求这样做)。

这是实际实现此目标的方法:

要使NSView控件通过其拖动事件来控制窗口,只需将其子类化并覆盖mouseDown即可,

class WindowDragView: NSView {

    override public func mouseDown(with event: NSEvent) {
        window?.performDrag(with: event)
    }

}

就是这样。 mouseDown函数将进一步的事件跟踪转移到其父窗口。

不需要isMovableByWindowBackgroundmouseDownCanMoveWindow的窗口遮罩。