NSPopover - 焦点丢失时隐藏 (在弹出窗口外单击)

作者:编程家 分类: objective 时间:2025-07-13

在macOS开发中,NSPopover是一个非常有用的组件,它可以用于创建弹出窗口。然而,当用户在弹出窗口外单击时,它默认情况下并不会自动隐藏。这可能会导致用户界面上的一些问题,因为弹出窗口会一直显示在屏幕上,直到用户手动关闭它。为了解决这个问题,我们可以通过监听焦点丢失事件,并在事件发生时隐藏NSPopover。

要实现这个功能,我们首先需要创建一个NSPopover的实例,并将其设置为我们想要显示的视图控制器的contentViewController属性。然后,我们可以通过实现NSPopoverDelegate协议中的popoverDidShow方法来监听弹出窗口的显示事件。在这个方法中,我们可以为主视图添加一个全局事件监视器,以便在用户单击弹出窗口外部时接收到焦点丢失事件。

下面是一个示例代码,演示了如何使用NSPopover和NSPopoverDelegate来实现焦点丢失时隐藏弹出窗口的功能:

swift

import Cocoa

class ViewController: NSViewController, NSPopoverDelegate {

var popover: NSPopover!

override func viewDidLoad() {

super.viewDidLoad()

popover = NSPopover()

popover.contentViewController = SomeViewController()

popover.delegate = self

}

func popoverDidShow(_ notification: Notification) {

if let window = view.window {

NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDown) { [weak self] event in

if let strongSelf = self {

if !window.frame.contains(event.locationInWindow) {

strongSelf.popover.performClose(nil)

}

}

}

}

}

}

class SomeViewController: NSViewController {

override func loadView() {

view = NSView(frame: NSRect(x: 0, y: 0, width: 200, height: 100))

view.wantsLayer = true

view.layer?.backgroundColor = NSColor.red.cgColor

}

}

在上面的代码中,我们首先创建了一个NSPopover的实例,并将其contentViewController属性设置为SomeViewController的实例。然后,我们将视图控制器的delegate属性设置为自身,以便能够监听popoverDidShow事件。

在popoverDidShow方法中,我们使用NSEvent的addGlobalMonitorForEvents方法添加了一个全局事件监视器。这个监视器会监听所有的鼠标左键单击事件,并在用户单击弹出窗口外部时触发。在事件处理程序中,我们首先检查事件发生的位置是否在主视图窗口的范围内。如果不在范围内,我们就调用popover的performClose方法来隐藏弹出窗口。

代码示例

上面的代码中,我们创建了一个NSViewController的子类SomeViewController,并在其loadView方法中创建了一个红色的NSView。这个视图将作为弹出窗口的内容显示。你可以根据自己的需要自定义视图的外观和布局。

使用NSPopoverDelegate监听焦点丢失事件

在上面的代码中,我们通过实现NSPopoverDelegate协议中的popoverDidShow方法来监听弹出窗口的显示事件。在这个方法中,我们添加了一个全局事件监视器,以便在用户单击弹出窗口外部时接收到焦点丢失事件。

隐藏弹出窗口

在焦点丢失事件处理程序中,我们使用popover的performClose方法来隐藏弹出窗口。这将导致弹出窗口消失,并且不再显示在屏幕上。

通过以上代码,我们成功实现了在焦点丢失时隐藏弹出窗口的功能。这样,当用户单击弹出窗口外部时,弹出窗口会自动隐藏,提升了用户界面的友好性和易用性。