如何在远离系统栏的地方打开一个NSPopover?
How to open a NSPopover at a distance from the system bar?
我正在打开 NSPopover
状态栏中的图标。
myPopover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
除了弹出窗口和系统栏的距离为零外,这工作正常:
我想获得与 Dropbox 应用程序相同的结果,该应用程序在距系统栏不远的地方呈现弹出框:
我试过使用 button.bounds.offsetBy(dx: 0.0, dy: 20.0)
,它不影响弹出窗口的位置,button.bounds.offsetBy(dx: 0.0, dy: -20.0)
将弹出窗口放在系统栏上方:
那么如何将 NSPopover
放置在距系统栏一定距离的位置?
首先,button.bounds.offsetBy(dx: 0.0, dy: -20.0)
不起作用的原因是因为那些坐标落在状态栏项目的 "window" 之外,即状态栏本身。所以它之外的任何东西都被裁剪了。
我通过到处收集信息解决了这个问题:
- 创建隐形 window.
- 找到状态栏项目在屏幕中的坐标,将不可见的window置于其下。
- 显示与不可见 window 相关的
NSPopover
,而不是状态栏项目。
红色的东西是看不见的window(用于演示目的)。
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
。要显示弹出窗口,必须传递一个视图。
您可以在显示弹出窗口后立即移动它的 contentView:
myPopover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
let popoverWindowX = myPopover.contentViewController?.view.window?.frame.origin.x ?? 0
let popoverWindowY = myPopover.contentViewController?.view.window?.frame.origin.y ?? 0
myPopover.contentViewController?.view.window?.setFrameOrigin(
NSPoint(x: popoverWindowX, y: popoverWindowY + 20)
)
myPopover.contentViewController?.view.window?.makeKey()
就 UI 而言,您会看到箭头略微滑动,但在您的情况下,填充非常小,几乎察觉不到。
我正在使用类似的东西来确保我的弹出框不会离开屏幕。你可以看到轻微的滑动。
我正在打开 NSPopover
状态栏中的图标。
myPopover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
除了弹出窗口和系统栏的距离为零外,这工作正常:
我想获得与 Dropbox 应用程序相同的结果,该应用程序在距系统栏不远的地方呈现弹出框:
我试过使用 button.bounds.offsetBy(dx: 0.0, dy: 20.0)
,它不影响弹出窗口的位置,button.bounds.offsetBy(dx: 0.0, dy: -20.0)
将弹出窗口放在系统栏上方:
那么如何将 NSPopover
放置在距系统栏一定距离的位置?
首先,button.bounds.offsetBy(dx: 0.0, dy: -20.0)
不起作用的原因是因为那些坐标落在状态栏项目的 "window" 之外,即状态栏本身。所以它之外的任何东西都被裁剪了。
我通过到处收集信息解决了这个问题:
- 创建隐形 window.
- 找到状态栏项目在屏幕中的坐标,将不可见的window置于其下。
- 显示与不可见 window 相关的
NSPopover
,而不是状态栏项目。
红色的东西是看不见的window(用于演示目的)。
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
。要显示弹出窗口,必须传递一个视图。
您可以在显示弹出窗口后立即移动它的 contentView:
myPopover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
let popoverWindowX = myPopover.contentViewController?.view.window?.frame.origin.x ?? 0
let popoverWindowY = myPopover.contentViewController?.view.window?.frame.origin.y ?? 0
myPopover.contentViewController?.view.window?.setFrameOrigin(
NSPoint(x: popoverWindowX, y: popoverWindowY + 20)
)
myPopover.contentViewController?.view.window?.makeKey()
就 UI 而言,您会看到箭头略微滑动,但在您的情况下,填充非常小,几乎察觉不到。
我正在使用类似的东西来确保我的弹出框不会离开屏幕。你可以看到轻微的滑动。