Navigieren zwischen Ansichten mit @EnvironmentObject in SwiftUI

Die Übersetzung des Artikels wurde am Vorabend des Starts des Fortgeschrittenenkurses "iOS Developer" vorbereitet .




Hallo und willkommen zu unserem Tutorial! In dieser Serie wird erläutert, wie Sie in SwiftUI zwischen Ansichten navigieren (ohne eine Navigationsansicht zu verwenden!). Diese Idee mag zwar trivial erscheinen, aber wenn wir sie etwas tiefer verstehen, können wir viel über die in SwiftUI verwendeten Datenflusskonzepte lernen.

Im vorherigen Teil haben wir gelernt, wie man dies mit implementiert @ObservableObject. In diesem Teil werden wir uns ansehen, wie Sie dasselbe tun, aber mit @EnvironmentObject effizienter. Wir werden auch eine kleine Übergangsanimation hinzufügen.

Folgendes werden wir erreichen:


Was wir haben


Wir haben gerade herausgefunden, wie Sie mit ObservableObject zwischen verschiedenen Ansichten navigieren können. Kurz gesagt, wir haben einen ViewRouter erstellt und ihn mit der Mutteransicht und unserer Inhaltsansicht verknüpft. Als Nächstes bearbeiten wir einfach die CurrentPage ViewRouter-Eigenschaft, indem wir auf die Schaltflächen der Inhaltsansicht klicken. Danach wird MotherView aktualisiert, um die entsprechende Inhaltsansicht anzuzeigen!

Es gibt jedoch einen zweiten, effizienteren Weg, um diese Funktionalität zu erreichen: Verwenden @EnvironmentObject!

Tipp: Hier können Sie die neuesten Entwicklungen herunterladen (dies ist der Ordner „NavigateInSwiftUIComplete“) : GitHub

Warum ObservableObjectist die Verwendung nicht die beste Lösung


Sie fragen sich wahrscheinlich: Warum sollten wir dies anders implementieren, wenn wir bereits eine funktionierende Lösung haben? Wenn Sie sich die Logik der Hierarchie unserer Anwendung ansehen, wird Ihnen dies klar. Unsere MotherView ist die Stammansicht, die die ViewRouter-Instanz initialisiert. In MotherView initialisieren wir auch ContentViewA und ContentViewB und übergeben ihnen die ViewRouter-Instanz als BindableObject.

Wie Sie sehen können, müssen wir einer strengen Hierarchie folgen, die ein initialisiertes ObservableObject stromabwärts an alle Unteransichten übergibt. Das ist nicht so wichtig, aber stellen Sie sich eine komplexere Anwendung mit vielen Ansichten vor. Wir müssen immer die Übertragung der initialisierten Observable-Stammansicht auf alle Unteransichten und alle Unteransichten von Unteransichten usw. verfolgen, was letztendlich eine ziemlich mühsame Aufgabe sein kann.



Zusammenfassend ObservableObjectlässt sich sagen, dass die Verwendung von clean bei komplexeren Anwendungshierarchien problematisch sein kann.

Stattdessen können wir den ViewRouter beim Start der Anwendung initialisieren, sodass alle Ansichten direkt mit dieser Instanz verbunden werden können, oder sie unabhängig von der Hierarchie der Anwendung überwachen. In diesem Fall sieht die ViewRouter-Instanz wie eine Cloud aus, die über den Code unserer Anwendung fliegt, auf die alle Ansichten automatisch zugreifen, ohne sich um die korrekte Initialisierungskette in der Ansichtshierarchie kümmern zu müssen.
Das ist nur der Job EnvironmentObject!

Was ist EnvironmentObject?


EnvironmentObjectIst ein Datenmodell, das nach der Initialisierung Daten mit allen Darstellungen Ihrer Anwendung austauschen kann. Was besonders gut ist, ist EnvironmentObjectdas ObservableObject, was durch die Bereitstellung geschaffen wird , damit wir unsere ViewRouterzum Erstellen verwenden können EnvironmentObject!

Sobald wir unsere ViewRouterals deklariert haben EnvironmentObject, können alle Darstellungen auf die gleiche Weise wie gewöhnliche Darstellungen daran angehängt werden ObservableObject, ohne dass eine Reihe von Initialisierungen in der Anwendungshierarchie erforderlich ist!

Wie bereits erwähnt, EnvironmentObjectsollte es bereits beim ersten Zugriff initialisiert werden. Da unsere MotherViewals Stammansicht die Eigenschaft betrachtet CurrentPage ViewRouter, müssen wir sie EnvironmentObjectbeim Start der Anwendung initialisieren . Dann können wir currentPage automatisch ändernEnvironmentObjectvon ContentView, was dann ein MotherViewerneutes Rendern erfordert.



Implementierung ViewRouteralsEnvironmentObject


Aktualisieren wir also den Code unserer Anwendung!

Ändern Sie zunächst den Wrapper der Eigenschaft viewRouterinnerhalb MotherViewvon @ObservableObjectvon @EnvironmentObject.

import SwiftUI

struct MotherView : View {
@EnvironmentObject var viewRouter: ViewRouter
var body: some View {
//...
    }
}

Die Immobilie viewRoutersucht jetzt ViewRouter-EnvironmentObject. Daher müssen wir unserer Struktur MotherView_Previewsdie entsprechende Instanz bereitstellen :

#if DEBUG
struct MotherView_Previews : PreviewProvider {
    static var previews: some View {
        MotherView().environmentObject(ViewRouter())
    }
}
#endif

Wie oben erwähnt - sollte unsere Anwendung beim Starten sofort mit einer Instanz ViewRouterin Qualität versehen werden EnvironmentObject, da sie MotherViewjetzt als Stammdarstellung bezeichnet wird EnvironmentObject. Aktualisieren Sie daher die Szenenfunktion in der Datei SceneDelegage.swiftwie folgt:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: MotherView().environmentObject(ViewRouter()))
            self.window = window
            window.makeKeyAndVisible()
        }
    }

Gut, jetzt, wenn Sie die Anwendung starten, erstellt SwiftUI eine Instanz ViewRouterin Qualität EnvironmentObject, an die jetzt alle Ansichten unserer Anwendung angehängt werden können.

Als nächstes aktualisieren wir unsere ContentViewA. Ändern Sie die viewRouterEigenschaft in EnvironmentObjectund aktualisieren Sie auch die Struktur ContentViewA_Previews.

import SwiftUI

struct ContentViewA : View {
    
    @EnvironmentObject var viewRouter: ViewRouter
    
    var body: some View {
       //...
    }
}
#if DEBUG
struct ContentViewA_Previews : PreviewProvider {
    static var previews: some View {
        ContentViewA().environmentObject(ViewRouter())
    }
}
#endif

Hinweis: Auch hier hat die Struktur ContentViewsA_Previewseine eigene Instanz ViewRouter, ist jedoch ContentViewAder Instanz zugeordnet, die beim Start der Anwendung erstellt wurde!

Wiederholen wir dies für ContentViewB:

import SwiftUI

struct ContentViewB : View {
    
    @EnvironmentObject var viewRouter: ViewRouter
    
    var body: some View {
        //...
    }
}
#if DEBUG
struct ContentViewB_Previews : PreviewProvider {
    static var previews: some View {
        ContentViewB().environmentObject(ViewRouter())
    }
}
#endif

Da viewRouterunsere Eigenschaften ContentViewjetzt direkt mit der ursprünglichen Instanz ViewRouterals verbunden sind / diese beobachten EnvironmentObject, müssen wir sie in unserer nicht mehr initialisieren MotherView. Also, aktualisieren wir unsere MotherView:

struct MotherView : View {
    
    @EnvironmentObject var viewRouter: ViewRouter
    
    var body: some View { 
        VStack {
            if viewRouter.currentPage == "page1" {
                ContentViewA()
            } else if viewRouter.currentPage == "page2" {
                ContentViewB()
            }
        }
    }
}

Das ist einfach großartig: Wir müssen nicht mehr ViewRouterin unserer initialisieren MotherViewund ihre Instanz an die ContentView weitergeben, was insbesondere bei komplexeren Hierarchien sehr effizient sein kann.

Großartig, lassen Sie uns unsere Anwendung ausführen und sehen, wie sie funktioniert.


Großartig, wir können uns immer noch zwischen unseren Ansichten bewegen!

Übergangsanimationen hinzufügen


Schauen wir uns als Bonus an, wie Sie beim Übergang von „Seite1“ zu „Seite2“ eine Übergangsanimation hinzufügen.

In SwiftUI ist dies recht einfach.
Schauen Sie sich die willChangeMethode an, mit der wir die Datei ViewRouter.swiftbei der CurrentPageAktualisierung aufrufen . Wie Sie bereits wissen, führt dies dazu, dass eine Bindung MotherViewIhren Körper erneut anzeigt und letztendlich einen anderen zeigt ContentView, was bedeutet, dass Sie zu einem anderen wechseln ContentView. Wir können Animationen hinzufügen, indem wir die Methode einfach willChangein eine Funktion einschließen withAnimation:

var currentPage: String = "page1" {
        didSet {
            withAnimation() {
                willChange.send(self)
            }
        }
    }

Jetzt können wir eine Übergangsanimation hinzufügen, wenn wir eine andere anzeigen Content View.
"WithAnimation (_: _ :) - gibt das Ergebnis der Neuberechnung des Ansichtskörpers mit der bereitgestellten Animation zurück"
Apple
Wir möchten unserer Anwendung beim Navigieren von ContentViewAnach einen Popup-Übergang bieten ContentViewB. Gehen Sie dazu zur Datei MotherView.swiftund fügen Sie beim Aufruf den Übergangsmodifikator hinzu ContentViewB. Sie können einen von mehreren vordefinierten Übergangstypen auswählen oder sogar einen eigenen erstellen (dies ist jedoch ein Thema für einen anderen Artikel). Um einen Popup-Übergang hinzuzufügen, wählen wir einen Typ aus .scale.

var body: some View {
        VStack {
            if viewRouter.currentPage == "page1" {
                ContentViewA()
            } else if viewRouter.currentPage == "page2" {
                ContentViewB()
                    .transition(.scale)
            }
        }
    }

Führen Sie Ihre Anwendung in einem regulären Simulator aus, um zu sehen, wie es funktioniert:


Cool, wir haben unserer Anwendung in nur wenigen Codezeilen eine schöne Übergangsanimation hinzugefügt!

Sie können den gesamten Quellcode hier herunterladen !

Fazit


Das ist alles! Wir haben gelernt, warum es besser ist, EnvironmentObjectzwischen Ansichten in SwiftUI zu navigieren und wie man sie implementiert. Wir haben auch gelernt, wie man der Navigation Übergangsanimationen hinzufügt. Wenn Sie mehr wissen möchten, folgen Sie uns auf Instagram und abonnieren Sie unseren Newsletter , um Updates, Tutorials und Tipps zu SwiftUI und vielem mehr nicht zu verpassen!



Kostenlose Lektion: „Beschleunigen von iOS-Apps mit Instrumenten“



All Articles