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")]
        })
    }
}

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)
          }
     }
}

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")]
        })
    }
}

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")]
        })
    }
}

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")]
        })
    }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.