Как создать панель меню приложения SwiftUI для macOS Big Sur

#swift #swiftui #desktop-application #xcode12 #macos-big-sur

#swift #свифтуи #desktop-приложение #xcode12 #macos-big-sur #swiftui

Вопрос:

Я пытаюсь создать приложение, которое отображается только в строке меню macOS Big Sur (верхний правый угол), следуя этому руководству: https://medium.com/@acwrightdesign/creating-a-macos-menu-bar-application-using-swiftui-54572a5d5f87/. Это работало на Xcode 11 и macOS Catalina, потому что был файл AppDelegate.swift, но я слышал, что это было заменено этим методом:

 @main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
  

Однако первые несколько шагов руководства требуют, чтобы я внес несколько изменений в (в настоящее время несуществующий) Файл AppDelegate.swift. Я пытался внести эти изменения в MyApp.swift, но, похоже, у меня не получается заставить его работать. Кто-нибудь хочет помочь мне адаптировать это руководство для macOS Big Sur / Xcode 12?

Примечание: вот как должен был выглядеть файл AppDelegate.swift (если он существовал) в соответствии с руководством (если вы по какой-либо причине не хотите открывать руководство):

 import Cocoa
import SwiftUI

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    var popover: NSPopover!
    var statusBarItem: NSStatusItem!
    
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // Create the SwiftUI view that provides the window contents.
        let contentView = ContentView()

        // Create the popover
        let popover = NSPopover()
        popover.contentSize = NSSize(width: 400, height: 500)
        popover.behavior = .transient
        popover.contentViewController = NSHostingController(rootView: contentView)
        self.popover = popover
        
        // Create the status item
        self.statusBarItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.variableLength))
        
        if let button = self.statusBarItem.button {
            button.image = NSImage(named: "Icon")
            button.action = #selector(togglePopover(_:))
        }
    }
    
    @objc func togglePopover(_ 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)
            }
        }
    }
    
}
  

Комментарии:

1. Вы все равно можете создать AppDelegate вместо использования нового жизненного цикла SwiftUI. Оно даже не устарело.

Ответ №1:

В вашем приложении используйте оболочку свойств NSApplicationDelegateAdaptor, чтобы сообщить SwiftUI, что он должен использовать ваш класс AppDelegate для делегирования приложения. Итак, ваш класс приложения должен выглядеть следующим образом:

 @main
struct MyApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
  

Ссылка на базу знаний

Комментарии:

1. Полное решение см. В этом репозитории .