SwiftUI ScrollView wird nicht aktualisiert?

10

Tor

Daten abrufen, die in a angezeigt werden sollen scrollView

erwartetes Ergebnis

Daten in der Bildlaufansicht angezeigt

Tatsächliche Ergebnis

eine leere Ansicht

Alternative

verwenden List, aber es ist nicht flexibel (kann keine Trennzeichen entfernen, kann nicht mehrere Spalten haben)

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
quelle
Ich habe dies auf Xcode 11.1, iOS 13.1, Swift 5 getestet und erhalte das erwartete Ergebnis (obwohl die Bildlaufansicht eher oben als in der Mitte ist).
sfung3
Sie brauchen auch nicht das Schlüsselwortreturn
sfung3
Interessant, ich bin auf Xcode 11.2, iOS 13.2, Swift 5
Youjin
Ja, ich hatte vorher eine printErklärung, daher derreturn
Youjin
Ich werde auf Xcode 11.2 aktualisieren und sehen, ob ich dies reproduzieren kann. Es kann eine Weile dauern, aber ich werde Sie über meine Ergebnisse auf dem Laufenden halten.
sfung3

Antworten:

10

Ein nicht so hackiger Weg, um dieses Problem zu umgehen, besteht darin, die ScrollView in eine IF-Anweisung einzuschließen, die prüft, ob das Array leer ist

if !self.array.isEmpty{
     ScrollView(.vertical) {
          ForEach(array) { o in
               Text(o.id)
          }
     }
}
paulaysabellemedina
quelle
Diese Problemumgehung ist perfekt, danke!
Hendrik
1

Das erwartete Verhalten tritt auf Xcode 11.1, aber nicht anXcode 11.2.1

Ich habe einen frameModifikator hinzugefügt , der ScrollViewdas ScrollViewerscheinen lässt

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
quelle
Leider nicht in der Lage, es auf iOS 13.2 auf Simulator zum
Laufen
1

Ich habe festgestellt, dass es wie erwartet funktioniert (Xcode 11.2), wenn der Status mit einem Wert initialisiert wird, nicht mit einem leeren Array. In diesem Fall funktioniert die Aktualisierung ordnungsgemäß und der Anfangszustand hat keine Auswirkung.

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
quelle
Das funktioniert für den einfachen Fall, in meinem Fall habe ich einen Netzwerkanruf onAppear, so dass das Initialisieren der scrollView mit Dummy-Daten problematisch sein kann
youjin
Richtig, aber diese Situation kann logisch im Code behandelt werden, da das ursprüngliche Objekt ein leicht zu erkennender Stub sein kann, der bedingt etwas wie "Laden" usw. anzeigt. Für mich war dies genug ... es lohnt sich zu teilen.
Asperi
1

Eine hackige Problemumgehung, die ich gefunden habe, besteht darin, Rectanglein der scrollView ein "unsichtbares" Element hinzuzufügen, wobei der widthWert auf einen Wert festgelegt wird, der größer ist als die Breite der Daten in derscrollView

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
quelle