SwiftUI ScrollView n'est pas mis à jour?

10

Objectif

Obtenez les données à afficher dans un scrollView

résultat attendu

données affichées dans scrollview

Résultat actuel

une vue vierge

Alternative

utiliser List, mais il n'est pas flexible (ne peut pas supprimer les séparateurs, ne peut pas avoir plusieurs colonnes)

Code

struct Object: Identifiable {
    var id: String
}

struct Test: View {
    @State var array = [Object]()

    var body: some View {
//        return VStack { // uncomment this to see that it works perfectly fine
        return ScrollView(.vertical) {
            ForEach(array) { o in
                Text(o.id)
            }
        }
        .onAppear(perform: {
            self.array = [Object(id: "1"),Object(id: "2"),Object(id: "3"),Object(id: "4"),Object(id: "5")]
        })
    }
}
youjin
la source
J'ai testé cela sur Xcode 11.1, iOS 13.1, Swift 5 et j'obtiens le résultat attendu (bien que la vue de défilement soit en haut plutôt qu'en centre).
sfung3
Vous n'avez pas non plus besoin du mot cléreturn
sfung3
intéressant, je suis sur Xcode 11.2, iOS 13.2, Swift 5
youjin
ouais j'avais une printdéclaration avant, d'où lereturn
youjin
Je vais mettre à jour vers Xcode 11.2 et voir si je peux le reproduire. Cela peut prendre un certain temps, mais je vais vous mettre à jour sur mes conclusions.
sfung3

Réponses:

10

Un moyen pas si hacky de contourner ce problème est de placer ScrollView dans une instruction IF qui vérifie si le tableau est vide

if !self.array.isEmpty{
     ScrollView(.vertical) {
          ForEach(array) { o in
               Text(o.id)
          }
     }
}
paulaysabellemedina
la source
Cette solution de contournement est parfaite, merci!
Hendrik
1

Le comportement attendu se produit Xcode 11.1mais n'est pas activéXcode 11.2.1

J'ai ajouté un framemodificateur ScrollViewqui fait ScrollViewapparaître

struct Object: Identifiable {
    var id: String
}

struct ContentView: View {
    @State var array = [Object]()

    var body: some View {
        ScrollView(.vertical) {
            ForEach(array) { o in
                Text(o.id)
            }
        }
        .frame(height: 40)
        .onAppear(perform: {
            self.array = [Object(id: "1"),Object(id: "2"),Object(id: "3"),Object(id: "4"),Object(id: "5")]
        })
    }
}
sfung3
la source
Malheureusement pas en mesure de le faire fonctionner sur iOS 13.2 sur Simulator
youjin
1

J'ai trouvé que cela fonctionne (Xcode 11.2) comme prévu si l'état est initialisé avec une certaine valeur, pas un tableau vide. Dans ce cas, la mise à jour fonctionne correctement et l'état initial n'a aucun effet.

struct TestScrollViewOnAppear: View {
    @State var array = [Object(id: "1")]

    var body: some View {
        ScrollView(.vertical) {
            ForEach(array) { o in
                Text(o.id)
            }
        }
        .onAppear(perform: {
            self.array = [Object(id: "1"),Object(id: "2"),Object(id: "3"),Object(id: "4"),Object(id: "5")]
        })
    }
}
Asperi
la source
cela fonctionne pour le cas simple, dans mon cas, j'ai un appel réseau onAppear, donc initialiser le scrollView avec des données factices peut être problématique
youjin
correct, mais cette situation peut être gérée logiquement dans le code, car l'objet initial peut être un stub facile à détecter pour montrer sous condition quelque chose comme le «chargement», etc. pour moi, cela suffisait ... donc ça vaut le coup de le partager.
Asperi
1

Une solution de contournement hacky que j'ai trouvée consiste à ajouter un "invisible" Rectangleà l'intérieur du scrollView, avec l' widthensemble à une valeur supérieure à la largeur des données dans lescrollView

struct Object: Identifiable {
    var id: String
}

struct ContentView: View {
    @State var array = [Object]()

    var body: some View {
        GeometryReader { geometry in
            ScrollView(.vertical) {
                Rectangle()
                    .frame(width: geometry.size.width, height: 0.01)
                ForEach(array) { o in
                    Text(o.id)
                }
            }
        }
        .onAppear(perform: {
            self.array = [Object(id: "1"),Object(id: "2"),Object(id: "3"),Object(id: "4"),Object(id: "5")]
        })
    }
}
youjin
la source