Menüleisten-App für macOS

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 Sie zuerst den Identitätsinspektor aus und ändern Sie die Klasse in QuotesViewController. Setzen Sie dann die Storyboard-ID auf QuotesViewController

Fügen Sie nun den folgenden Code am Ende der Datei QuotesViewController.swift hinzu :

 extension QuotesViewController { // MARK: Storyboard instantiation static func freshController() -> QuotesViewController { //1. let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil) //2. let identifier = NSStoryboard.SceneIdentifier("QuotesViewController") //3. guard let viewcontroller = storyboard.instantiateController(withIdentifier: identifier) as? QuotesViewController else { fatalError("Why cant i find QuotesViewController? - Check Main.storyboard") } return viewcontroller } } 

Was ist hier los:

  1. Wir bekommen einen Link zu Main.storyboard .
  2. Erstellen Sie eine Szenen-ID , die mit der oben installierten übereinstimmt.
  3. 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.

 // MARK: Actions extension QuotesViewController { @IBAction func previous(_ sender: NSButton) { } @IBAction func next(_ sender: NSButton) { } @IBAction func quit(_ sender: NSButton) { } } 

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 .

Source: https://habr.com/ru/post/de447754/


All Articles