La traduction de l'article a été préparée à la veille du lancement du cours avancé "iOS Developer" .
Bonjour et bienvenue dans notre tutoriel! Dans cette série, nous expliquons comment naviguer entre les vues dans SwiftUI (sans utiliser une vue de navigation!). Bien que cette idée puisse sembler banale, mais en la comprenant un peu plus profondément, nous pouvons en apprendre beaucoup sur les concepts de flux de données utilisés dans SwiftUI.Dans la partie précédente, nous avons appris à implémenter cela en utilisant @ObservableObject
. Dans cette partie, nous verrons comment faire de même, mais plus efficacement en utilisant @EnvironmentObject. Nous allons également ajouter une petite animation de transition.Voici ce que nous allons réaliser:Ce que nous avons
Donc, nous venons de comprendre comment naviguer entre différentes vues à l'aide d'ObservableObject. En bref, nous avons créé un ViewRouter et l'avons associé à Mother View et à notre Content View. Ensuite, nous manipulons simplement la propriété CurrentPage ViewRouter en cliquant sur les boutons Content View. Après cela, MotherView est mis à jour pour afficher la vue de contenu correspondante!Mais il existe un deuxième moyen plus efficace pour atteindre cette fonctionnalité: utiliser @EnvironmentObject
!Astuce: Vous pouvez télécharger les derniers développements ici (c'est le dossier «NavigateInSwiftUIComplete») : GitHubPourquoi l'utilisation ObservableObject
n'est pas la meilleure solution
Vous vous demandez probablement: pourquoi devrions-nous implémenter cela d'une autre manière, alors que nous avons déjà une solution de travail? Eh bien, si vous regardez la logique de la hiérarchie de notre application, cela deviendra clair pour vous. Notre MotherView est la vue racine qui initialise l'instance de ViewRouter. Dans MotherView, nous initialisons également ContentViewA et ContentViewB, en leur passant l'instance ViewRouter en tant que BindableObject.Comme vous pouvez le voir, nous devons suivre une hiérarchie stricte qui transmet un ObservableObject initialisé en aval à toutes les sous-vues. Maintenant, ce n'est pas si important, mais imaginez une application plus complexe avec beaucoup de vues. Nous devons toujours garder une trace de la transmission de la vue racine observable initialisée à toutes les sous-vues et toutes les sous-vues des sous-vues, etc., ce qui peut finalement devenir une tâche assez fastidieuse.
Pour résumer: l'utilisation de clean ObservableObject
peut être problématique lorsqu'il s'agit de hiérarchies d'applications plus complexes.Au lieu de cela, nous pourrions initialiser le ViewRouter au démarrage de l'application afin que toutes les vues puissent être directement connectées à cette instance, ou plutôt la regarder, quelle que soit la hiérarchie de l'application. Dans ce cas, l'instance de ViewRouter ressemblera à un nuage qui survole le code de notre application, auquel toutes les vues accèdent automatiquement sans se soucier de la chaîne d'initialisation correcte dans la hiérarchie des vues.C'est juste le boulot EnvironmentObject
!Qu'est-ce que c'est EnvironmentObject
?
EnvironmentObject
Est un modèle de données qui, après l'initialisation, peut échanger des données avec toutes les représentations de votre application. Ce qui est particulièrement bon, c'est ce qui est EnvironmentObject
créé en fournissant ObservableObject
, afin que nous puissions utiliser le nôtre ViewRouter
pour créer EnvironmentObject
!Dès que nous nous déclarions ViewRouter
que EnvironmentObject
, toutes les représentations peuvent être attachées à de la même manière que pour les ordinaires ObservableObject
, mais sans la nécessité d'une chaîne de initialisations dans la hiérarchie de l' application!Comme déjà mentionné, il EnvironmentObject
doit déjà être initialisé lors du premier accès. Étant donné que la nôtre MotherView
, en tant que vue racine, examinera la propriété CurrentPage
ViewRouter
, nous devons l'initialiser au EnvironmentObject
démarrage de l'application. Ensuite, nous pouvons automatiquement changer currentPageEnvironmentObject
de ContentView
, ce qui appelle alors MotherView
un nouveau rendu.
Mise ViewRouter
en œuvre en tant queEnvironmentObject
Alors, mettons à jour le code de notre application!Tout d'abord, changez le wrapper de la propriété à l' viewRouter
intérieur MotherView
de @ObservableObject
en @EnvironmentObject
.import SwiftUI
struct MotherView : View {
@EnvironmentObject var viewRouter: ViewRouter
var body: some View {
}
}
La propriété est viewRouter
maintenant à la recherche ViewRouter-EnvironmentObject
. Ainsi, nous devons fournir à notre structure MotherView_Previews
l'instance appropriée:#if DEBUG
struct MotherView_Previews : PreviewProvider {
static var previews: some View {
MotherView().environmentObject(ViewRouter())
}
}
#endif
Comme mentionné ci-dessus - lors du démarrage de notre application, il devrait être immédiatement fourni avec une instance ViewRouter
de qualité EnvironmentObject
, car elle MotherView
fait maintenant référence à la représentation racine EnvironmentObject
. Par conséquent, mettez à jour la fonction de scène à l'intérieur du fichier SceneDelegage.swift
comme suit: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()
}
}
Très bien, maintenant lorsque vous démarrez l'application, SwiftUI crée une instance ViewRouter
de qualité EnvironmentObject
, à laquelle toutes les vues de notre application peuvent maintenant être attachées.Ensuite, mettons à jour le nôtre ContentViewA
. Modifiez sa viewRouter
propriété en EnvironmentObject
et mettez également à jour la structure 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
Astuce: Encore une fois, la structure ContentViewsA_Previews
a sa propre instance ViewRouter
, mais ContentViewA
est associée à l'instance créée lors du lancement de l'application!Répétons ceci pour 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
Puisque viewRouter
nos propriétés sont ContentView
maintenant directement liées à / observons l'instance initiale ViewRouter
as EnvironmentObject
, nous n'avons plus besoin de les initialiser dans la nôtre MotherView
. Alors, mettons à jour notre MotherView
:struct MotherView : View {
@EnvironmentObject var viewRouter: ViewRouter
var body: some View {
VStack {
if viewRouter.currentPage == "page1" {
ContentViewA()
} else if viewRouter.currentPage == "page2" {
ContentViewB()
}
}
}
}
C'est tout simplement génial: nous n'avons plus besoin d'initialiser à l' ViewRouter
intérieur de la nôtre MotherView
et de transmettre son instance à ContentView, ce qui peut être très efficace, en particulier pour les hiérarchies plus complexes.Très bien, exécutons notre application et voyons comment cela fonctionne. Génial, nous pouvons toujours nous déplacer entre nos vues!Ajout d'animations de transition
En bonus, voyons comment ajouter une animation de transition lors du passage de «page1» à «page2».Dans SwiftUI, c'est assez simple.Regardez la willChange
méthode que nous appelons le fichier ViewRouter.swift
lors de la CurrentPage
mise à jour. Comme vous le savez déjà, cela provoque une reliure MotherView
pour réafficher votre corps, en montrant finalement un autre ContentView
, ce qui signifie passer à un autre ContentView
. Nous pouvons ajouter une animation en enveloppant simplement la méthode willChange
dans une fonction withAnimation
:var currentPage: String = "page1" {
didSet {
withAnimation() {
willChange.send(self)
}
}
}
Nous pouvons maintenant ajouter une animation de transition lors de l'affichage d'une autre Content View
."WithAnimation (_: _ :) - renvoie le résultat du recalcul du corps de la vue avec l'animation fournie"
Apple
Nous voulons fournir à notre application une transition contextuelle lors de la navigation de ContentViewA
à ContentViewB
. Pour ce faire, accédez au fichier MotherView.swift
et ajoutez le modificateur de transition lors de l'appel ContentViewB
. Vous pouvez choisir l'un des nombreux types de transition prédéfinis ou même créer le vôtre (mais c'est un sujet pour un autre article). Pour ajouter une transition contextuelle, nous sélectionnons un type .scale
.var body: some View {
VStack {
if viewRouter.currentPage == "page1" {
ContentViewA()
} else if viewRouter.currentPage == "page2" {
ContentViewB()
.transition(.scale)
}
}
}
Pour voir comment cela fonctionne, exécutez votre application dans un simulateur ordinaire: Cool, nous avons ajouté une belle animation de transition à notre application en quelques lignes de code!Vous pouvez télécharger tout le code source ici !Conclusion
C'est tout! Nous avons appris pourquoi il est préférable d'utiliser EnvironmentObject
pour naviguer entre les vues dans SwiftUI et comment l'implémenter. Nous avons également appris à ajouter des animations de transition à la navigation. Si vous voulez en savoir plus, suivez-nous sur Instagram et abonnez-vous à notre newsletter pour ne pas manquer les mises à jour, tutoriels et astuces sur SwiftUI et bien plus encore!
Leçon gratuite: «Accélérer les applications iOS avec des instruments»