Avec le code suivant:
struct HomeView: View {
var body: some View {
NavigationView {
List(dataTypes) { dataType in
NavigationLink(destination: AnotherView()) {
HomeViewRow(dataType: dataType)
}
}
}
}
}
Ce qui est bizarre, quand HomeView
apparaît, NavigationLink
charge immédiatement le AnotherView
. Par conséquent, toutes les dépendances AnotherView
sont également chargées, même si elles ne sont pas encore visibles à l'écran. L'utilisateur doit cliquer sur la ligne pour la faire apparaître. Mon AnotherView
contient un DataSource
, où diverses choses se produisent. Le problème est que l'ensemble DataSource
est chargé à ce stade, y compris certains temporisateurs, etc.
Est-ce que je fais quelque chose de mal..? Comment le gérer de telle manière que AnotherView
se charge une fois que l'utilisateur appuie sur cette HomeViewRow
?
Il faut un ForEach
personnalisé pour faire ce que vous demandez car le générateur de fonctions doit évaluer l'expression
NavigationLink(destination: AnotherView()) {
HomeViewRow(dataType: dataType)
}
pour que chaque ligne visible puisse afficher HomeViewRow(dataType:)
, auquel cas AnotherView()
doit également être initialisé.
Pour éviter cela, un ForEach
personnalisé est nécessaire.
import SwiftUI
struct LoadLaterView: View {
var body: some View {
HomeView()
}
}
struct DataType: Identifiable {
let id = UUID()
var i: Int
}
struct ForEachLazyNavigationLink<Data: RandomAccessCollection, Content: View, Destination: View>: View where Data.Element: Identifiable {
var data: Data
var destination: (Data.Element) -> (Destination)
var content: (Data.Element) -> (Content)
@State var selected: Data.Element? = nil
@State var active: Bool = false
var body: some View {
VStack{
NavigationLink(destination: {
VStack{
if self.selected != nil {
self.destination(self.selected!)
} else {
EmptyView()
}
}
}(), isActive: $active){
Text("Hidden navigation link")
.background(Color.orange)
.hidden()
}
List{
ForEach(data) { (element: Data.Element) in
Button(action: {
self.selected = element
self.active = true
}) { self.content(element) }
}
}
}
}
}
struct HomeView: View {
@State var dataTypes: [DataType] = {
return (0...99).map{
return DataType(i: $0)
}
}()
var body: some View {
NavigationView{
ForEachLazyNavigationLink(data: dataTypes, destination: {
return AnotherView(i: $0.i)
}, content: {
return HomeViewRow(dataType: $0)
})
}
}
}
struct HomeViewRow: View {
var dataType: DataType
var body: some View {
Text("Home View \(dataType.i)")
}
}
struct AnotherView: View {
init(i: Int) {
print("Init AnotherView \(i.description)")
self.i = i
}
var i: Int
var body: some View {
print("Loading AnotherView \(i.description)")
return Text("hello \(i.description)").onAppear {
print("onAppear AnotherView \(self.i.description)")
}
}
}
J'ai eu le même problème où j'aurais pu avoir une liste de 50 éléments, qui a ensuite chargé 50 vues pour la vue de détail qui appelait une API (ce qui a entraîné le téléchargement de 50 images supplémentaires).
La réponse pour moi a été d'utiliser .onAppear pour déclencher toute la logique qui doit être exécutée lorsque la vue apparaît à l'écran (comme désactiver vos minuteries).
struct AnotherView: View {
var body: some View {
VStack{
Text("Hello World!")
}.onAppear {
print("I only printed when the view appeared")
// trigger whatever you need to here instead of on init
}
}
}