Eine macOS-Anwendung mit Seitenleiste


Mit der Veröffentlichung von macOS Big Sur hat Apple viele der eigenen Anwendungen auf ein neues Design umgestellt. Programme verfügen jetzt auf der linken Seite des Fensters über eine schmale Seitenleiste, der Arbeitsbereich befindet sich rechts daneben. Oft wird dieses Layout für eine Master-Detail-Navigation verwendet. Nach Auswahl eines Elements aus der Seitenleiste ändert sich die Ansicht im Arbeitsbereich. Nicht selten wird dabei die komplette View getauscht. Die Anwendungen Musik, Notizen oder Erinnerungen sind nur drei Beispiele, die diesem Design folgen.

Dieses Tutorial soll zeigen, wie ein Programm mit dem beschriebenen Layout in SwiftUI entwickelt werden kann. Die Anwendung soll die folgenden Anforderungen erfüllen:

  • Es gibt eine globale Akzentfarbe für die komplette Anwendung
  • Das Programmfenster hat eine Seitenleiste
  • Das Programmfenster hat eine Werkzeugleiste mit Symbolen als Schaltflächen
  • Eine Schaltfläche übernimmt die Funktion, die Seitenleiste auf und zu zuklappen
  • Die Seitenleiste enthält eine Liste von Elementen, die durch anklicken die primäre Ansicht im Arbeitsbereich des Programmfenster tauschen
  • Dem Programm soll im Menü ein weiterer Punkt mit Unterpunkten hinzugefügt werden

Die Akzentfarbe

Der erste Schritt der Entwicklung ist einfach. Die Akzentfarbe kann mit wenigen Handgriffe festgelegt werden. Im Projektnavigator die Datei Assets.xcassets wählen, und anschließend dort das ColorSet AccentColor. Über die Farbauswahl im Attributes Inspector kann dann die gewünschte Farbe bestimmt werden.

Stacks Image 205

Zwei Views für den Arbeitsbereich

Der folgende Schritt ist ebenfalls nicht schwer. Um im Arbeitsbereich unterschiedliche Views anzuzeigen, müssen diese erzeugt werden. In einem umfangreichen Programm kann einen View durchaus aus mehreren einzelnen Views zusammengesetzt werden. Im Rahmen dieses Tutorials genügen Texte, mit denen die beiden Views im laufenden Programm zu unterscheiden sind. In diesem Beispiel heißen die beiden Ansichten MainView und SettingsView.

struct MainViewView {

    var body: some View {

        Text("MainView").font(.headline)

    }

}


struct SettingsViewView {

    var body: some View {

        Text("Settings").font(.headline)

    }

}

Die Seitenleiste

Die Seitenleiste, in Dokumentationen von Apple auch aus Source List bezeichnet, ist ebenfalls eine eigenständige View. Sie enthält eine List und darin eingebettet zwei NaviagtionLink, mit denen später der MainView und der SettingsView angezeigt werden. Jeder NaviagtionLink einhält ein Label. Dies ist ein Steuerelement, welches sich aus einer Kombination von Text und Icon zusammensetzt. In den von Apple angebotenen Systemicons gibt es eine reichhaltige Auswahl. Der List wird der Stil SidebarListStyle zugewiesen.

struct SidebarViewView {

    var body: some View {

        List {

            NavigationLink(destination: MainView()) {

                Label("MainView", systemImage: "paperplane.fill")}

            

            NavigationLink(destination: SettingsView()) {

                Label("Settings", systemImage: "gearshape.fill")}

            

        }.listStyle(SidebarListStyle())

    }

}

Die App.swift

Zusammengesetzt wird das Fenster in der von App abgeleiteten Struktur, die Xcode zusammen mit dem Projekt erzeugt hat. Der Name der Klasse ist abhängig vom Projektnamen. In diesem Fall DemoApp.swift. Die wichtigste Komponente ist die WindowGroup. Dieser Gruppe ist ein NaviagtionView untergeordnet, der wiederum den SidebarView und den MainView enthält. Der MainView wird somit automatisch zu der Ansicht, die angezeigt wird, wenn das Programm startet.

@main

struct DemoAppApp {

   var body: some Scene {

        WindowGroup {

            NavigationView {

                SidebarView()

                MainView()                   

            }

        }

    }

}

Die grundlegende Funktionalität der Anwendung ist damit erreicht. Das Fenster hat eine Seitenleiste, mit der die beiden Ansichten MainView und SettingsView ausgewählt und angezeigt werden können.

Stacks Image 224

Eine Toolbar für das Fenster

Die Möglichkeit, die Seitenleiste auf und zu zuklappen, kann über eine Toolbar erreicht werden, die dem NavigationView zugewiesen wird. Die Toolbar einhält ein ToolbarItem und das wiederum einen Button. Aufgerufen wird beim Anklicken der Schaltfläche die Methode ToggleSidebar. Sie verändert die Sichtbarkeit der Seitenleiste. Durch die Angabe von placement: .navigation wird das Item links von dem Fenstertitel platziert.

Der Zustand der Seitenleiste wird automatisch gespeichert. Wird das Programm mit einer ausgeblendeten Seitenleiste beendet, ist sie beim nächsten Programmstart weiterhin nicht sichtbar.

@main

struct DemoAppApp {

    

    var body: some Scene {

        WindowGroup {

            NavigationView {

                SidebarView()

                MainView()                   

            }

            .toolbar {

                ToolbarItem(placement: .navigation) {

                    Button(action: { ToggleSidebar() })

                        { Image(systemName: "sidebar.left")}}

            }

        }

   }

    

    func ToggleSidebar() {

        NSApp.keyWindow?.firstResponder?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil)

    }

}

Stacks Image 216

Weitere ToolbarItems sollen dem Fenster rechts vom Titel hinzugefügt werden. Das funktioniert über das placement: .primaryAction.

@main

struct DemoAppApp {

    

    var body: some Scene {

        WindowGroup {

            NavigationView {

                SidebarView()

                MainView()                   

            }

            .toolbar {

                ToolbarItem(placement: .navigation) {

                    Button(action: { ToggleSidebar() })

                        { Image(systemName: "sidebar.left")}}

                

                ToolbarItem(placement: .primaryAction) {

                    Button(action: { /* Action*/  })

                        { Image(systemName: "folder.fill")}}


                ToolbarItem(placement: .primaryAction) {

                    Button(action: { /* Action*/  })

                        { Image(systemName: "trash.fill")}}

            }

        }

    }

    

    func ToggleSidebar() {

        NSApp.keyWindow?.firstResponder?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil)

    }

}

Stacks Image 212

Durch zwei weitere Modifier kann das Design des Fensters und der Toolbar ein wenig angepasst werden. Durch Setzen des UnifiedCompactWindowToolbarStyle für den Stil der Toolbar wird die Werkzeugleiste schmaler und die Icons kleiner. Soll über der Arbeitsbereich keine Toolbar angezeigt werden, muss der Stil des Fensters auf HiddenTitleBarWindowStyle gesetzt werden. Die Icons und Buttons der Werkzeugleiste verschwinden dabei nicht. Stattdessen werden sie am oberen Rand des Arbeitsbereiches eingebettet. Es gibt dann keine farbliche Abtrennung mehr zwischen Toolbar und dem Rest des Fensters. Die beiden Stile können einzeln oder gemeinsam verwendet werden. Jeder wird durch der HiddenTitleBarWindowStyle auch der Fenstertitel verborgen und alle ToolbatItems werden linksbündig platziert.

@main

struct DemoAppApp {

    

    var body: some Scene {

        WindowGroup {

            NavigationView {

                SidebarView()

                MainView()                   

            }

            .toolbar {

                ToolbarItem(placement: .navigation) {

                    Button(action: { ToggleSidebar() })

                        { Image(systemName: "sidebar.left")}}

                

                ToolbarItem(placement: .primaryAction) {

                    Button(action: { /* Action*/  })

                        { Image(systemName: "folder.fill")}}


                ToolbarItem(placement: .primaryAction) {

                    Button(action: { /* Action*/  })

                        { Image(systemName: "trash.fill")}}

            }

        }

        .windowToolbarStyle(UnifiedCompactWindowToolbarStyle())

        .windowStyle(HiddenTitleBarWindowStyle())

    }

    

    func ToggleSidebar() {

        NSApp.keyWindow?.firstResponder?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil)

    }

}

Stacks Image 209

Das Menü

Um die Menüleiste der Anwendung um einen weiteren Menüpunkt zu erweitern, muss der WindowGroup ein CommandMenu hinzugefügt werden. Der neue Menüpunkt befindet sich anschließend immer zwischen den vorhandenen Menüpunkten View und Window.

.commands {

        CommandMenu("Werkzeuge") {

            Button(action: { print("Untermenü 1") }) {

                Text("Untermenü 1")

            }

            Button(action: { print("Untermenü 2") }) {

                Text("Untermenü 2")

            }

            Button(action: { print("Untermenü 3") }) {

                Text("Untermenü 3")

            }

        }

    } 

Stacks Image 220

Geschrieben am: 21.03.2021
Technologien: SwiftUI, macOS