• 作者:老汪软件技巧
  • 发表时间:2024-10-15 00:01
  • 浏览量:

最近属实是睡不着系列,SwiftUI 精通之路的分享目前在搁置,因为目前自己在尝试开发自己的第一款软件,是壁纸类的 MacOS 应用程序,所以自己也在学习一些 AppKit框架,今天分享下这个 NSPopover.behavior 这个弹出层类的属性,它主要可以做什么!

在 macos 开发中,NSPopover 是一个类,允许你在应用程序的用户界面中显示浮动的弹出窗口。

.behavior 属性主要是用于控制弹出窗口的行为,特别是用户与其进行交互时的响应。

它主要有这几变量:.transient, .semitransient, .applicationDefined, .modal

1 .transient

注意: 这种类型的弹出窗口通常在用户与应用程序的其他部分进行交互时消失。

2 .semitransient

3 .applicationDefined:

4 .modal:

下面示例案例展示如何创建一个 NSPopover 并且其行为设置为.transient

import AppKit
class AppDelegate: NSObject, NSApplicationDelegate {
    var popover: NSPopover!
    func applicationDidFinishLanuching(_ notification: Notification) {
        popover = NSPopover()
        popover.contentSize = NSSize(width: 300, height: 200)
        popover.behavior = .transient
        popover.contentViewController = NSViewController() // 设置内容视图控制器
    }
}
NSPopover.show(relativeTo positioningRect: NSRect, of positioningView: NSView, preferredEdge: NSRectEdge)

NSPopover.show(relativeTo:of:preferredEdge:) 是 NSPopover 用来显示弹出窗口的方法。通过这个方法,你可以将 NSPopover 相对于某个视图显示出来,并决定箭头的位置。它的具体参数如下:

方法定义

func show(relativeTo positioningRect: NSRect, of positioningView: NSView, preferredEdge: NSRectEdge)

参数介绍

relativeTo positioningRect: NSRect

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

of positioningView: NSViewpreferredEdge: NSRectEdge

假设你有一个状态栏按钮,你希望弹出层从按钮上方弹出,带有指向按钮的箭头。你可以使用如下代码:


if let button = statusBarItem.button {
    popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
}

在这个例子中:

relativeTo: button.bounds 表示弹出层的位置相对于按钮的边界进行定位。

of: button 表示弹出层会在这个按钮附近弹出。

preferredEdge: .minY 表示弹出层的箭头应该指向按钮的顶部,弹出层会从按钮的上方出现。

以下是一个完整的示例,展示如何在状态栏按钮上方显示带有箭头的 NSPopover:

class AppDelegate: NSObject, NSApplicationDelegate {
    var statusBarItem: NSStatusItem!
    var popoverWindow: NSPopover!
 
    func applicationDidFinishLaunching(_ notification: Notification) {
        createStatusBarSymbol()
        createPopoverWindow()
    }
 
    func createStatusBarSymbol() {
        statusBarItem = NSStatusBar.system.statusItem(withLength:NSStatusItem.variableLength)
        let image = NSImage(systemSymbolName: "photo.stack.fill",accessibilityDescription: "")
        image?.size = NSSize(width: 25, height: 25)
        image?.isTemplate = true
        statusBarItem.button?.image = image
        statusBarItem.button?.action = #selector(handleStatusButton)
        statusBarItem.button?.target = self
    }
    func createPopoverWindow() {
        popoverWindow = NSPopover()
        popoverWindow.contentSize = NSSize(width: 300, height: 400)
        popoverWindow.behavior = .transient
        popoverWindow.contentViewController = NSHostingController(rootView: ContentView())
    }
  
    @objc
    func handleStatusButton() {
        if let button = statusBarItem.button {
            // 弹出 Popover
            if popoverWindow.isShown {
                popoverWindow.performClose(nil)
            } else {
                popoverWindow.show(relativeTo: button.bounds, of: button,preferredEdge: .minY)
            }
        }
    }
}

在这个例子中,NSPopover 会从状态栏按钮的上方弹出,并带有指向该按钮的箭头。

对于 relativeTo 这个属性的通俗的解释:

relativeTo 参数指定的是弹出层相对于某个视图(比如按钮)的位置矩形,它帮助你定义 NSPopover 弹出的位置。简单来说,relativeTo 是告诉系统,弹出层应该“靠近”哪部分显示。

假设你有一个按钮(或其他视图),当用户点击这个按钮时,弹出层会显示出来。relativeTo 就是指 这个弹出层应该以按钮的哪个部分为参考位置。通常,这个矩形是按钮的大小和位置。你可以理解为:

通常,设置为 button.bounds, 表示弹出层相对于整个按钮区域弹出。

举个形象的例子:

想象有一张纸(button.bounds 就是纸的大小),你要在这张纸的旁边(或上面、下面)放一个盒子(就是 NSPopover)。relativeTo 就是这张纸的位置和大小,告诉系统你想让盒子放在纸的哪个方向。

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

这段代码做的事情就是:

如果你换成 .maxY,弹出层就会从按钮的下方出现。