我正在状态栏中通过图标操作打开NSPopover

myPopover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)

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

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

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

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

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

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

那么,如何将NSPopover放置在距系统栏一定距离的地方?

最佳答案

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

我通过在这里和那里收集信息来解决了这个问题:

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

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

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

    swift 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)
    }
    

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

    10-05 22:49