macOS Catalina中NSAlert作为Sheet靠近屏幕边缘显示异常求助
I’ve run into similar odd hardware-specific behavior with sheet alerts before—frustrating when the same code acts differently on identical OS versions! Unfortunately, there’s no built-in system preference to force sheets to always stay visible, but we can fix this with a bit of code. Here are three actionable approaches:
1. Adjust Main Window Position Before Showing the Alert
Before presenting the sheet, check if the window’s position would cause the alert to get clipped by the screen edge, then nudge the window inward. Use NSScreen to get the visible screen frame (excluding menu bar and dock) and calculate overlaps:
func showAlertWithoutClipping(_ alert: NSAlert, from window: NSWindow) { guard let screen = window.screen else { alert.beginSheetModal(for: window) return } let screenVisibleFrame = screen.visibleFrame var windowFrame = window.frame // Check if window bottom is below screen visible area (sheets show at bottom) let bottomOffset = screenVisibleFrame.minY - windowFrame.minY if bottomOffset > 0 { windowFrame.origin.y += bottomOffset + 10 // Add small buffer for spacing window.setFrame(windowFrame, display: true, animate: true) } // Check right edge (in case sheet extends right on some layouts) let rightOffset = windowFrame.maxX - screenVisibleFrame.maxX if rightOffset > 0 { windowFrame.origin.x -= rightOffset + 10 window.setFrame(windowFrame, display: true, animate: true) } alert.beginSheetModal(for: window) }
This ensures the sheet has enough space to display fully before it’s presented.
2. Switch to a Popover Alert
If moving the main window isn’t ideal, present the alert content in an NSPopover instead. Popovers automatically reposition themselves to stay within the screen bounds, so you won’t have clipping issues. You’ll need to replicate the alert’s UI in the popover’s content view, but it’s a clean alternative:
func showPopoverAlert(with message: String, from view: NSView) { let popover = NSPopover() popover.behavior = .transient // Create a custom view to match native alert style let contentView = NSView(frame: NSRect(x: 0, y: 0, width: 300, height: 120)) contentView.wantsLayer = true contentView.layer?.cornerRadius = 8 contentView.layer?.backgroundColor = NSColor.windowBackgroundColor.cgColor let messageLabel = NSTextField(labelWithString: message) messageLabel.font = .systemFont(ofSize: 14) messageLabel.alignment = .center messageLabel.frame = NSRect(x: 20, y: 60, width: 260, height: 20) messageLabel.isEditable = false messageLabel.isBordered = false messageLabel.backgroundColor = .clear contentView.addSubview(messageLabel) let okButton = NSButton(title: "OK", target: self, action: #selector(dismissPopover)) okButton.frame = NSRect(x: 110, y: 20, width: 80, height: 32) contentView.addSubview(okButton) let contentVC = NSViewController() contentVC.view = contentView popover.contentViewController = contentVC popover.show(relativeTo: view.bounds, of: view, preferredEdge: .minY) } @objc func dismissPopover() { // Dismiss the popover by accessing it from the sender's superview hierarchy guard let button = sender as? NSButton, let popover = button.window?.popover else { return } popover.close() }
3. Report the Bug to Apple
Since this is a hardware-specific inconsistency with identical macOS versions, it’s likely a system-level edge case that Apple hasn’t addressed yet. You should report this through Apple’s official feedback channel to help them fix it in future OS updates.
内容的提问来源于stack exchange,提问作者stapoz

