Anwendungen in der Menüleiste sind MacOS-Benutzern seit langem bekannt. Einige dieser Anwendungen haben einen „normalen“ Teil, andere befinden sich nur in der Menüleiste.
In diesem Handbuch schreiben Sie eine Anwendung, in der mehrere Zitate berühmter Personen in einem Popup-Fenster angezeigt werden. Beim Erstellen dieser Anwendung lernen Sie Folgendes:
- Anwendungssymbol in der Menüleiste zuweisen
- Die Anwendung wird nur in der Menüleiste gehostet
- Benutzerdefiniertes Menü hinzufügen
- Zeigen Sie auf Wunsch des Benutzers ein Popup-Fenster an und blenden Sie es bei Bedarf mithilfe der Ereignisüberwachung aus
Hinweis: In diesem Handbuch wird davon ausgegangen, dass Sie mit Swift und macOS vertraut sind.
Erste Schritte
Starten Sie Xcode. Wählen Sie als Nächstes im Menü 
Datei / Neu / Projekt ... die Vorlage 
macOS / Anwendung / Kakao-App aus und klicken Sie auf 
Weiter .
Geben Sie im nächsten Bildschirm Angebote als 
Produktnamen ein und wählen Sie Ihren 
Organisationsnamen und Ihre 
Organisationskennung aus . Stellen Sie dann sicher, dass Swift als Anwendungssprache ausgewählt und das Kontrollkästchen 
Storyboards verwenden aktiviert ist. Deaktivieren Sie die Kontrollkästchen 
Dokumentbasierte Anwendung erstellen , 
Kerndaten verwenden , Komponententests einschließen und 
UI-Tests einschließen .

Klicken Sie 
abschließend erneut auf 
Weiter , geben Sie den Speicherort für das Projekt an und klicken Sie auf 
Erstellen .
Öffnen Sie nach dem 
Erstellen des neuen Projekts 
AppDelegate.swift und fügen Sie der Klasse die folgende Eigenschaft hinzu:
let statusItem = NSStatusBar.system.statusItem(withLength:NSStatusItem.squareLength) 
Hier erstellen wir in der Menüleiste Statuselement (Anwendungssymbol) eine feste Länge, die für Benutzer sichtbar ist.
Dann müssen wir unser Bild diesem neuen Element in der Menüleiste zuweisen, damit wir unsere neue Anwendung unterscheiden können.
Gehen Sie im Projektnavigator zu Assets.xcassets, 
laden Sie ein Bild hoch und ziehen Sie es in den Asset-Katalog.
Wählen Sie ein Bild aus und öffnen Sie den Attributinspektor. Ändern Sie die Option 
Rendern als in 
Vorlagenbild .

Wenn Sie ein eigenes Bild verwenden, stellen Sie sicher, dass das Bild schwarzweiß ist, und konfigurieren Sie es als 
Vorlagenbild, damit das Symbol sowohl in der dunklen als auch in der hellen Menüleiste gut aussieht.
Gehen Sie zurück zu 
AppDelegate.swift und fügen Sie den folgenden Code zu 
applicationDidFinishLaunching (_ :) hinzu. if let button = statusItem.button { button.image = NSImage(named:NSImage.Name("StatusBarButtonImage")) button.action = #selector(printQuote(_:)) } 
Hier weisen wir das Anwendungssymbol zu, das wir gerade zum Anwendungssymbol hinzugefügt haben, und weisen eine 
Aktion zu, wenn wir darauf klicken.
Fügen Sie der Klasse die folgende Methode hinzu:
 @objc func printQuote(_ sender: Any?) { let quoteText = "Never put off until tomorrow what you can do the day after tomorrow." let quoteAuthor = "Mark Twain" print("\(quoteText) — \(quoteAuthor)") } 
Diese Methode druckt einfach das Zitat auf die Konsole.
Beachten Sie die 
objc- Methodenrichtlinie. Auf diese Weise können Sie diese Methode als Antwort auf einen Schaltflächenklick verwenden.
Erstellen Sie die Anwendung und führen Sie sie aus. Die neue Anwendung wird in der Menüleiste angezeigt. Hurra!
Jedes Mal, wenn Sie auf das Symbol in der Menüleiste klicken, wird das berühmte Sprichwort von Mark Twain in der Xcode-Konsole angezeigt.
Wir verstecken das Hauptfenster und das Symbol im Dock
Es gibt ein paar kleine Dinge, die wir tun müssen, bevor wir uns direkt mit der Funktionalität befassen:
- Dock-Symbol löschen
- Entfernen Sie unnötiges Hauptfenster der Anwendung
Öffnen Sie die 
Info.plist, um das Dock-Symbol zu entfernen. Fügen Sie einen neuen 
UIElement- Schlüssel 
(Application is Agent) hinzu und setzen Sie seinen Wert auf 
YES .

Jetzt ist es an der Zeit, sich mit dem Hauptanwendungsfenster zu befassen.
- Öffnen Sie das Main.storyboard
- Wählen Sie Window Controller-Szene und löschen Sie sie
- View Controller Szene verlassen, wir werden es bald verwenden

Erstellen Sie die Anwendung und führen Sie sie aus. Jetzt hat die Anwendung nicht mehr sowohl das Hauptfenster als auch das unnötige Symbol im Dock. Großartig!
Menü zum Statuselement hinzufügen
Eine Antwort mit einem Klick reicht für eine ernsthafte Anwendung eindeutig nicht aus. Der einfachste Weg, Funktionen hinzuzufügen, ist das Hinzufügen eines Menüs. Fügen Sie diese Funktion am Ende von 
AppDelegate hinzu .
 func constructMenu() { let menu = NSMenu() menu.addItem(NSMenuItem(title: "Print Quote", action: #selector(AppDelegate.printQuote(_:)), keyEquivalent: "P")) menu.addItem(NSMenuItem.separator()) menu.addItem(NSMenuItem(title: "Quit Quotes", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")) statusItem.menu = menu } 
Fügen Sie diesen Aufruf am Ende von 
applicationDidFinishLaunching (_ :) hinzu. constructMenu() 
Wir erstellen 
NSMenu , fügen 3 Instanzen von 
NSMenuItem hinzu und legen dieses Menü als Anwendungssymbolmenü fest.
Einige wichtige Punkte:
- Der Titel des Menüelements ist der Text, der im Menü angezeigt wird. Ein guter Ort, um die Anwendung zu lokalisieren (falls erforderlich).
- Aktion ist wie die Aktion einer Schaltfläche oder eines anderen Steuerelements eine Methode, die aufgerufen wird, wenn der Benutzer auf einen Menüpunkt klickt
- keyEquivalent ist eine Tastenkombination, mit der Sie einen Menüpunkt auswählen können. Kleinbuchstaben verwenden Cmd als Modifikator und Kleinbuchstaben verwenden Cmd + Umschalt . Dies funktioniert nur, wenn sich die Anwendung ganz oben befindet und aktiv ist. In unserem Fall ist es erforderlich, dass das Menü oder ein anderes Fenster sichtbar ist, da unsere Anwendung kein Symbol im Dock hat
- separatorItem ist ein inaktiver Menüpunkt in Form einer grauen Linie zwischen anderen Elementen. Verwenden Sie es zum Gruppieren
- printQuote ist die Methode, die Sie bereits in AppDelegate definiert haben , und terminate ist die von NSApplication definierte Methode .
Starten Sie die Anwendung und Sie sehen ein Menü, indem Sie auf das Anwendungssymbol klicken.

Klicken Sie auf das Menü. Wenn Sie Angebot drucken auswählen, wird das Angebot in der Xcode-Konsole angezeigt, und 
Angebote beenden beendet die Anwendung.
Fügen Sie ein Popup hinzu
Sie haben gesehen, wie einfach es ist, ein Menü aus dem Code hinzuzufügen, aber das Anzeigen eines Zitats in der Xcode-Konsole entspricht eindeutig nicht den Erwartungen der Benutzer an die Anwendung. Jetzt fügen wir einen einfachen Ansichts-Controller hinzu, um Anführungszeichen auf die richtige Weise anzuzeigen.
Gehen Sie zum Menü 
Datei / Neu / Datei ... , wählen Sie die Vorlage 
macOS / Source / Cocoa Class aus und klicken Sie auf 
Weiter .

- Nennen Sie die Klasse QuotesViewController
- Machen Sie einen Erben von NSViewController
- Stellen Sie sicher, dass das Kontrollkästchen Auch XIB-Datei für Benutzeroberfläche erstellen nicht aktiviert ist
- Stellen Sie die Sprache auf Swift ein
Klicken Sie 
abschließend erneut auf 
Weiter , wählen Sie einen Speicherort für die Datei aus und klicken Sie auf 
Erstellen .
Öffnen 
Sie nun 
Main.storyboard . Erweitern Sie 
View Controller Scene und wählen Sie 
View Controller-Instanz aus .
 Wählen
Wählen Sie zuerst den 
Identitätsinspektor aus und ändern Sie die Klasse in 
QuotesViewController. Setzen Sie dann die 
Storyboard-ID auf 
QuotesViewControllerFügen Sie nun den folgenden Code am Ende der Datei 
QuotesViewController.swift hinzu :
 extension QuotesViewController {  
Was ist hier los:
- Wir bekommen einen Link zu Main.storyboard .
- Erstellen Sie eine Szenen-ID , die mit der oben installierten übereinstimmt.
- Erstellen Sie eine Instanz von QuotesViewController und geben Sie sie zurück.
Sie erstellen diese Methode, sodass jetzt jeder, der den 
QuotesViewController verwendet, nicht mehr wissen muss, wie er erstellt wird. Es funktioniert einfach.
Beachten Sie den 
fatalError in der 
Guard- Anweisung. Es kann hilfreich sein, es oder 
assertionFailure zu verwenden, damit Sie selbst und die anderen Mitglieder des Entwicklungsteams Bescheid wissen, wenn etwas in der Entwicklung schief geht.
Nun zurück zu 
AppDelegate.swift . Fügen Sie eine neue Eigenschaft hinzu.
 let popover = NSPopover() 
Ersetzen Sie dann ein 
pplicationDidFinishLaunching (_ :) durch den folgenden Code:
 func applicationDidFinishLaunching(_ aNotification: Notification) { if let button = statusItem.button { button.image = NSImage(named:NSImage.Name("StatusBarButtonImage")) button.action = #selector(togglePopover(_:)) } popover.contentViewController = QuotesViewController.freshController() } 
Sie haben die 
Klickaktion geändert, um die Methode 
togglePopover (_ :) aufzurufen , die wir etwas später schreiben werden. Anstatt ein Menü zu konfigurieren und hinzuzufügen, haben wir ein Popup-Fenster konfiguriert, in dem etwas von 
QuotesViewController angezeigt wird .
Fügen Sie 
AppDelegate die folgenden drei Methoden 
hinzu :
 @objc func togglePopover(_ sender: Any?) { if popover.isShown { closePopover(sender: sender) } else { showPopover(sender: sender) } } func showPopover(sender: Any?) { if let button = statusItem.button { popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY) } } func closePopover(sender: Any?) { popover.performClose(sender) } 
showPopover () zeigt ein Popup. Sie geben nur an, woher es kommt, macOS positioniert es und zeichnet einen Pfeil, als würde er in der Menüleiste angezeigt.
closePopover () schließt nur das Popup, und 
togglePopover () ist eine Methode, die das Popup je nach Status entweder 
ein- oder 
ausblendet .
Starten Sie die Anwendung und klicken Sie auf das entsprechende Symbol.

Alles ist in Ordnung, aber wo ist der Inhalt?
Wir implementieren den Quote View Controller
Zunächst benötigen Sie ein Modell zum Speichern von Anführungszeichen und Attributen. Gehen Sie zum Menü 
Datei / Neu / Datei ... und wählen Sie die 
Vorlage macOS / Quelle / Swift-Datei und dann 
Weiter . Benennen Sie die Datei 
Quote und klicken Sie auf 
Create .
Öffnen Sie die Datei 
Quote.swift und fügen Sie den folgenden Code hinzu:
 struct Quote { let text: String let author: String static let all: [Quote] = [ Quote(text: "Never put off until tomorrow what you can do the day after tomorrow.", author: "Mark Twain"), Quote(text: "Efficiency is doing better what is already being done.", author: "Peter Drucker"), Quote(text: "To infinity and beyond!", author: "Buzz Lightyear"), Quote(text: "May the Force be with you.", author: "Han Solo"), Quote(text: "Simplicity is the ultimate sophistication", author: "Leonardo da Vinci"), Quote(text: "It's not just what it looks like and feels like. Design is how it works.", author: "Steve Jobs") ] } extension Quote: CustomStringConvertible { var description: String { return "\"\(text)\" — \(author)" } } 
Hier definieren wir eine einfache Anführungszeichenstruktur und eine statische Eigenschaft, die alle Anführungszeichen zurückgibt. Da wir 
Quote mit dem 
CustomStringConvertible- Protokoll kompatibel 
gemacht haben , können wir problemlos bequem formatierten Text erhalten.
Es gibt Fortschritte, aber wir brauchen noch Steuerelemente, um all dies anzuzeigen.
Fügen Sie Schnittstellenelemente hinzu
Öffnen Sie Main.storyboard und ziehen Sie 3 Tasten (Drucktaste) und Beschriftung (Mehrzeilige Beschriftung 
) auf dem Ansichts-Controller heraus.
Positionieren Sie die Schaltflächen und Beschriftungen so, dass sie ungefähr so aussehen:

Befestigen Sie den linken Knopf mit einem Abstand von 20 am linken Rand und zentrieren Sie ihn vertikal.
Befestigen Sie den rechten Knopf mit einem Abstand von 20 am rechten Rand und zentrieren Sie ihn vertikal.
Befestigen Sie den unteren Knopf mit einem Abstand von 20 an der Unterkante und zentrieren Sie ihn horizontal.
Befestigen Sie den linken und rechten Rand der Markierung mit einem Abstand von 20 in vertikaler Mitte an den Schaltflächen.

Sie werden mehrere Layoutfehler sehen, da nicht genügend Informationen für das 
automatische Layout vorhanden sind, um dies herauszufinden.
Setzen Sie die 
Priorität für das 
Umarmen horizontaler Inhalte auf 249, damit die Größe des Etiketts geändert werden kann.

Gehen Sie nun wie folgt vor:
- Setzen Sie das Bild mit der linken Schaltfläche auf NSGoLeftTemplate und löschen Sie den Titel
- Setzen Sie das Bild mit der rechten Schaltfläche auf NSGoRightTemplate und löschen Sie den Titel
- Setzen Sie den Titel der Schaltfläche unten auf Quit Quotes .
- Stellen Sie die Textausrichtung des Etiketts auf Mitte ein.
- Überprüfen Sie, ob der Zeilenumbruch am Etikett auf Zeilenumbruch eingestellt ist .
Öffnen 
Sie nun 
QuotesViewController.swift und fügen Sie der Implementierung der 
QuotesViewController- Klasse den folgenden Code 
hinzu :
 @IBOutlet var textLabel: NSTextField! 
Fügen Sie diese Erweiterung der Klassenimplementierung hinzu. In 
QuotesViewController.swift gibt es jetzt zwei Klassenerweiterungen.
 
Wir haben gerade eine 
Steckdose für das Etikett hinzugefügt, mit dem wir Anführungszeichen anzeigen, und drei Stub-Methoden, die wir mit den Schaltflächen verbinden.
Verbinden des Codes mit Interface Builder
Hinweis: Xcode hat Kreise links von Ihrem Code platziert - neben den Schlüsselwörtern 
IBAction und 
IBOutlet .

Wir werden sie verwenden, um den Code mit der Benutzeroberfläche zu verbinden.
Klicken Sie bei 
gedrückter Alt- Taste im 
Projektnavigator auf 
Main.storyboard . Daher wird das 
Storyboard im 
Assistenten-Editor rechts und der Code links geöffnet.
Ziehen Sie den Kreis links von 
textLabel auf die Beschriftung im 
Interface Builder . Kombinieren Sie auf die gleiche Weise die 
vorherigen , 
nächsten und 
Beendigungsmethoden mit den Schaltflächen links, rechts und unten.

Starten Sie Ihre Anwendung.

Wir haben die Standard-Popup-Größe verwendet. Wenn Sie ein größeres oder kleineres Popup möchten, ändern Sie einfach die Größe im 
Storyboard .
Schreiben eines Codes für die Schaltflächen
Wenn Sie den 
Assistenten-Editor noch nicht ausgeblendet haben, klicken Sie auf 
Befehlsrückgabe oder 
Ansicht> Standardeditor> Standardeditor anzeigenÖffnen Sie 
QuotesViewController.swift und fügen Sie der 
Klassenimplementierung die folgenden Eigenschaften hinzu:
 let quotes = Quote.all var currentQuoteIndex: Int = 0 { didSet { updateQuote() } } 
Die 
Anführungszeichen- Eigenschaft enthält alle Anführungszeichen, und 
currentQuoteIndex ist der Index des 
Angebots , das derzeit angezeigt wird. 
CurrentQuoteIndex verfügt außerdem über einen 
Eigenschaftsbeobachter, mit dem der Inhalt des Etiketts mit einem neuen Anführungszeichen aktualisiert werden kann, wenn sich der Index ändert.
Fügen Sie nun die folgenden Methoden hinzu:
 override func viewDidLoad() { super.viewDidLoad() currentQuoteIndex = 0 } func updateQuote() { textLabel.stringValue = String(describing: quotes[currentQuoteIndex]) } 
Wenn die Ansicht geladen wird, setzen wir den Anführungszeichenindex auf 0, was wiederum zu einer Aktualisierung der Schnittstelle führt. 
updateQuote () aktualisiert einfach die 
Textbezeichnung , um ein Zitat anzuzeigen. entsprechender 
currentQuoteIndex .
Aktualisieren Sie diese Methoden abschließend mit dem folgenden Code:
 @IBAction func previous(_ sender: NSButton) { currentQuoteIndex = (currentQuoteIndex - 1 + quotes.count) % quotes.count } @IBAction func next(_ sender: NSButton) { currentQuoteIndex = (currentQuoteIndex + 1) % quotes.count } @IBAction func quit(_ sender: NSButton) { NSApplication.shared.terminate(sender) } 
Die Methoden 
next () und 
previous () durchlaufen alle Zitate. 
Beenden schließt die Anwendung.
Starten Sie die App:

Ereignisüberwachung
Es gibt noch eine Sache, die Benutzer von unserer Anwendung erwarten - das Popup-Fenster auszublenden, wenn der Benutzer irgendwo außerhalb darauf klickt. Dazu benötigen wir einen Mechanismus namens 
macOS global event monitor .
Erstellen Sie eine neue Swift-Datei, nennen Sie sie 
EventMonitor und ersetzen Sie ihren Inhalt durch den folgenden Code:
 import Cocoa public class EventMonitor { private var monitor: Any? private let mask: NSEvent.EventTypeMask private let handler: (NSEvent?) -> Void public init(mask: NSEvent.EventTypeMask, handler: @escaping (NSEvent?) -> Void) { self.mask = mask self.handler = handler } deinit { stop() } public func start() { monitor = NSEvent.addGlobalMonitorForEvents(matching: mask, handler: handler) } public func stop() { if monitor != nil { NSEvent.removeMonitor(monitor!) monitor = nil } } } 
Beim Initialisieren einer Instanz dieser Klasse übergeben wir ihr eine Ereignismaske, die wir abhören werden (z. B. Tastenanschläge, Mausrad-Bildlauf usw.), und einen Ereignishandler.
Wenn wir mit dem Abhören 
beginnen möchten, ruft 
start () addGlobalMonitorForEventsMatchingMask (_: handler :) auf , das das zu speichernde Objekt zurückgibt. Sobald das in der Maske enthaltene Ereignis eintritt, ruft das System Ihren Handler auf.
Um die Überwachung von Ereignissen zu stoppen, wird 
removeMonitor () in 
stop () aufgerufen und wir löschen das Objekt, indem wir es auf nil setzen.
Wir müssen nur noch 
start () und 
stop () zum richtigen Zeitpunkt aufrufen. Die Klasse ruft auch 
stop () auf dem Deinitializer auf, um zu bereinigen.
Event Monitor verbinden
Öffnen Sie 
AppDelegate.swift ein letztes Mal und fügen Sie eine neue Eigenschaft hinzu:
 var eventMonitor: EventMonitor? 
Fügen Sie dann diesen Code hinzu, um den 
Ereignismonitor am Ende von 
applicationDidFinishLaunching (_ :) zu konfigurieren.
 eventMonitor = EventMonitor(mask: [.leftMouseDown, .rightMouseDown]) { [weak self] event in if let strongSelf = self, strongSelf.popover.isShown { strongSelf.closePopover(sender: event) } } 
Dies informiert Ihre Anwendung, wenn Sie auf die linke oder rechte Schaltfläche klicken. Bitte beachten Sie: Der Handler wird nicht als Reaktion auf Mausklicks in Ihrer Anwendung aufgerufen. Aus diesem Grund wird das Popup nicht geschlossen, während Sie darauf klicken.
Wir verwenden einen 
schwachen Bezug zu sich 
selbst , um die Gefahr eines Zyklus starker Verbindungen zwischen 
AppDelegate und 
EventMonitor zu vermeiden.
Fügen Sie am Ende der 
showPopover (_ :) -Methode den folgenden Code hinzu:
 eventMonitor?.start() 
Hier beginnen wir mit der Überwachung von Ereignissen, wenn ein Popup-Fenster angezeigt wird.
Fügen Sie nun den Code am Ende der Methode 
closePopover (_ :) hinzu :
 eventMonitor?.stop() 
Hier beenden wir die Überwachung, wenn das Popup geschlossen wird.
Die Bewerbung ist fertig!
Fazit
Hier finden Sie den vollständigen Code für dieses Projekt.
Sie haben gelernt, wie Sie das Menü und das Popup in der Anwendung in der Menüleiste einstellen. Warum nicht mit mehreren Tags oder formatiertem Text experimentieren, um die Anführungszeichen besser sehen zu können? Oder ein Backend anschließen, um Angebote aus dem Internet zu erhalten? Oder möchten Sie mit der Tastatur zwischen Anführungszeichen navigieren?
Ein guter Ort zum Recherchieren ist die offizielle Dokumentation: 
NSMenu , 
NSPopover und 
NSStatusItem .