如何在距系统栏一定距离的地方打开NSPopover?

Pie*_*ier 2 macos cocoa nsstatusbar nspopover swift

我正在NSPopover状态栏中打开一个带有图标的动作。

myPopover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
Run Code Online (Sandbox Code Playgroud)

除弹出窗口和系统栏的距离为零外,这可以正常工作:

在此处输入图片说明

我想获得与Dropbox应用相同的结果,该应用将Popover呈现在距系统栏一小段距离的位置:

在此处输入图片说明

我试过使用button.bounds.offsetBy(dx: 0.0, dy: 20.0)不会影响弹出窗口的位置并且button.bounds.offsetBy(dx: 0.0, dy: -20.0)将弹出窗口置于系统栏上方的方法:

在此处输入图片说明

那么如何将其定位NSPopover在距系统栏一定距离的地方?

Pie*_*ier 5

首先,之所以button.bounds.offsetBy(dx: 0.0, dy: -20.0)不起作用,是因为这些坐标落在状态栏项目本身即状态栏项目的“窗口”之外。所以它外面的任何东西都被裁剪掉了。

我通过到处收集信息来解决了这个问题:

  1. 创建一个不可见的窗口。
  2. 在状态栏项目的屏幕中找到坐标,并将不可见的窗口置于其下方。
  3. 显示与NSPopover不可见窗口相关的信息,而不是状态栏项。

在此处输入图片说明

红色的是不可见的窗口(出于演示目的)。

迅捷4(Xcode 9.2)

// Create a window
let invisibleWindow = NSWindow(contentRect: NSMakeRect(0, 0, 20, 5), styleMask: .borderless, backing: .buffered, defer: false)
invisibleWindow.backgroundColor = .red
invisibleWindow.alphaValue = 0

if let button = statusBarItem.button {
    // find the coordinates of the statusBarItem in screen space
    let buttonRect:NSRect = button.convert(button.bounds, to: nil)
    let screenRect:NSRect = button.window!.convertToScreen(buttonRect)

    // calculate the bottom center position (10 is the half of the window width)
    let posX = screenRect.origin.x + (screenRect.width / 2) - 10
    let posY = screenRect.origin.y

    // position and show the window
    invisibleWindow.setFrameOrigin(NSPoint(x: posX, y: posY))
    invisibleWindow.makeKeyAndOrderFront(self)

    // position and show the NSPopover
    mainPopover.show(relativeTo: invisibleWindow.contentView!.frame, of: invisibleWindow.contentView!, preferredEdge: NSRectEdge.minY)
    NSApp.activate(ignoringOtherApps: true)
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试使用show(relativeTo: invisibleWindow.frame ...),弹出窗口没有出现,因为NSWindow不是NSView。为了显示弹出窗口,必须通过一个视图。