如何使用SwiftUI在macOS中创建状态栏图标和菜单

2fjabf4q  于 2022-11-21  发布在  Swift
关注(0)|答案(3)|浏览(286)

什么是SwiftUI API用于创建状态栏菜单?
根据辅助功能检查器,苹果似乎在电池和WiFi菜单中使用了SwiftUI视图。
第一次

编辑:

将解决方案作为单独的答案发布。

igsr9ssn

igsr9ssn1#

  • 由于这个问题最近受到了更多关注,而唯一的答复并不能完全解决问题,我想重复我问题的编辑部分,并将其标记为已解决。*
  • Edit2:添加了一段额外的代码,允许使用SwiftUI视图作为状态栏图标。可能对显示动态徽章很方便。*

找到了一种方法来在swiftui中显示这一点,而不需要烦人的NSPopover。尽管我使用AppDelegate的applicationDidFinishLaunching来执行代码,但它可以从应用的任何位置调用,即使是在SwiftUI生命周期应用中。
代码如下:

func applicationDidFinishLaunching(_ aNotification: Notification) {
        // SwiftUI content view & a hosting view
        // Don't forget to set the frame, otherwise it won't be shown.
        //
        let contentViewSwiftUI = VStack {
            Color.blue
            Text("Test Text")
            Color.white
        }
        let contentView = NSHostingView(rootView: contentViewSwiftUI)
        contentView.frame = NSRect(x: 0, y: 0, width: 200, height: 200)
        
        // Status bar icon SwiftUI view & a hosting view.
        //
        let iconSwiftUI = ZStack(alignment:.center) {
            Rectangle()
                .fill(Color.green)
                .cornerRadius(5)
                .padding(2)
                
            Text("3")
                .background(
                    Circle()
                        .fill(Color.blue)
                        .frame(width: 15, height: 15)
                )
                .frame(maxWidth: .infinity, maxHeight: .infinity,  alignment: .bottomTrailing)
                .padding(.trailing, 5)
        }
        let iconView = NSHostingView(rootView: iconSwiftUI)
        iconView.frame = NSRect(x: 0, y: 0, width: 40, height: 22)
        
        // Creating a menu item & the menu to add them later into the status bar
        //
        let menuItem = NSMenuItem()
        menuItem.view = contentView
        let menu = NSMenu()
        menu.addItem(menuItem)
        
        // Adding content view to the status bar
        //
        let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
        statusItem.menu = menu
        
        // Adding the status bar icon
        //
        statusItem.button?.addSubview(iconView)
        statusItem.button?.frame = iconView.frame

        // StatusItem is stored as a property.
        self.statusItem = statusItem
    }

bvjxkvbb

bvjxkvbb2#

在AppDelegate中添加以下代码:

// Create the status item in the Menu bar 
self.statusBarItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.variableLength))

// Add a menu and a menu item
let menu = NSMenu()
let editMenuItem = NSMenuItem()
editMenuItem.title = "Edit"
menu.addItem(editMenuItem)

//Set the menu 
self.statusBarItem.menu = menu

//This is the button which appears in the Status bar
if let button = self.statusBarItem.button {
    button.title = "Here"
}

这会将具有自定义菜单的按钮添加到MenuBar。

编辑-如何使用SwiftUI视图

正如您所问,这里是如何使用SwiftUI视图的答案。
首先创建一个NSPopover,然后将SwiftUI视图 Package 在一个NSHostingController中。

var popover: NSPopover

let popover = NSPopover()
popover.contentSize = NSSize(width: 350, height: 350)
popover.behavior = .transient
popover.contentViewController = NSHostingController(rootView: contentView)
    self.popover = popover

然后,切换弹出窗口,而不是显示NSM菜单:

self.statusBarItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.variableLength))
if let button = self.statusBarItem.button {
     button.title = "Click"
     button.action = #selector(showPopover(_:))
}

执行以下操作:

@objc func showPopover(_ sender: AnyObject?) {
    if let button = self.statusBarItem.button
    {
        if self.popover.isShown {
            self.popover.performClose(sender)
        } else {
            self.popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
        }
    }
}

yyyllmsg

yyyllmsg3#

额外菜单栏

在macOS 13.0+和Xcode 14.0+中,MenuBarExtra结构允许您创建一个系统菜单栏,类似于NSStatusBar的图标和菜单。当指定的绑定设置为true时,MenuBarExtra的项目将显示在系统菜单栏中。

import SwiftUI

@available(macOS 13.0, *)                       // macOS Ventura
@main struct StatusBarApp: App {
    
    @State private var command: String = "A"
       
    var body: some Scene {

        MenuBarExtra(command, systemImage: "\(command).circle") {
           
            Button("Uno") { command = "A" }
                .keyboardShortcut("U")
           
            Button("Dos") { command = "B" }
                .keyboardShortcut("D")
           
            Divider()

            Button("Salir") { NSApplication.shared.terminate(nil) }
                .keyboardShortcut("S")
        }
    }
}

从Dock中删除应用程序图标

在Xcode的Info标签中,选取Application is agent (UIElement)并将其值设定为YES

相关问题