SwiftUI ScrollView nie jest aktualizowany?

10

Cel

Uzyskaj dane do wyświetlenia w scrollView

Spodziewany wynik

dane pokazane w widoku przewijania

Aktualny rezultat

pusty widok

Alternatywny

użyj List, ale nie jest elastyczny (nie można usunąć separatorów, nie może mieć wielu kolumn)

Kod

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
źródło
Przetestowałem to na Xcode 11.1, iOS 13.1, Swift 5 i otrzymuję oczekiwany wynik (chociaż widok przewijania jest na górze, a nie na środku).
sfung3
Nie potrzebujesz również słowa kluczowegoreturn
sfung3,
ciekawe, jestem na Xcode 11.2, iOS 13.2, Swift 5
youjin
tak, miałem już printoświadczenie, stądreturn
youjin
Zaktualizuję do Xcode 11.2 i zobaczę, czy mogę to odtworzyć. Może to chwilę potrwać, ale poinformuję cię o moich odkryciach.
sfung3

Odpowiedzi:

10

Nie tak hackowanym sposobem na obejście tego problemu jest umieszczenie ScrollView w instrukcji IF, która sprawdza, czy tablica jest pusta

if !self.array.isEmpty{
     ScrollView(.vertical) {
          ForEach(array) { o in
               Text(o.id)
          }
     }
}
paulaysabellemedina
źródło
To obejście jest idealne, dziękuję!
Hendrik
1

Oczekiwane zachowanie występuje w dniu Xcode 11.1 ale nieXcode 11.2.1

Dodałem framemodyfikator do ScrollViewktórego się ScrollViewpojawiają

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
źródło
Niestety nie można go uruchomić w systemie iOS 13.2 na symulatorze
youjin
1

Przekonałem się, że działa (Xcode 11.2) zgodnie z oczekiwaniami, jeśli stan został zainicjowany z pewną wartością, a nie pustą tablicą. W takim przypadku aktualizacja działa poprawnie, a stan początkowy nie ma wpływu.

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
źródło
to działa w prostym przypadku, w moim przypadku mam połączenie sieciowe onAppear, więc zainicjowanie scrollView z fałszywymi danymi może być problematyczne
youjin
poprawne, ale tę sytuację można rozwiązać logicznie w kodzie, ponieważ początkowy obiekt może być łatwym do wykrycia odcinkiem, aby wyświetlić warunkowo coś takiego jak „ładowanie” itp. Dla mnie to wystarczyło… więc warto się nim podzielić.
Asperi,
1

Jednym z okropnych obejść, które znalazłem, jest dodanie „niewidocznego” Rectanglewewnątrz scrollView, przy widthustawieniu wartości większej niż szerokość danych wscrollView

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
źródło