SwiftUI ScrollView non viene aggiornato?


10

Obbiettivo

Ottieni dati da visualizzare in a scrollView

Risultato atteso

dati mostrati in scrollview

Risultato attuale

una vista vuota

Alternativa

utilizzare List, ma non è flessibile (non è possibile rimuovere i separatori, non può avere più colonne)

Codice

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

Ho provato questo su Xcode 11.1, iOS 13.1, Swift 5 e sto ottenendo il risultato atteso (anche se la vista di scorrimento è in alto anziché al centro).
sfung3

Inoltre non hai bisogno della parola chiavereturn
sfung3

interessante, sono su Xcode 11.2, iOS 13.2, Swift 5
youjin

sì, ho avuto una printdichiarazione prima, quindi ilreturn
youjin

Aggiornerò Xcode 11.2 e vedrò se riesco a riprodurlo. Potrebbe volerci un po ', ma ti aggiornerò sulle mie scoperte.
sfung3

Risposte:


10

Un modo non così complicato per aggirare questo problema è racchiudere ScrollView in un'istruzione IF che controlla se l'array è vuoto

if !self.array.isEmpty{
     ScrollView(.vertical) {
          ForEach(array) { o in
               Text(o.id)
          }
     }
}

Questa soluzione alternativa è perfetta, grazie!
Hendrik il

1

Il comportamento previsto si verifica Xcode 11.1ma non si attivaXcode 11.2.1

Ho aggiunto un framemodificatore al ScrollViewquale far ScrollViewapparire

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

Sfortunatamente non riesco a farlo funzionare su iOS 13.2 su Simulator
youjin

1

Ho scoperto che funziona (Xcode 11.2) come previsto se lo stato inizializzato con un certo valore, non con un array vuoto. In questo caso l'aggiornamento funziona correttamente e lo stato iniziale non ha alcun effetto.

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

che funziona per il semplice caso, nel mio caso ho una chiamata di rete onAppear, quindi l'inizializzazione di scrollView con dati fittizi può essere problematica
youjin

corretto, ma questa situazione può essere gestita logicamente nel codice, perché l'oggetto iniziale può essere un troncone facilmente rilevabile per mostrare in modo condizionale qualcosa come "caricamento" ecc. per me questo è stato abbastanza ... quindi vale la pena condividere.
Asperi

1

Una soluzione aleatoria che ho trovato è quella di aggiungere un "invisibile" Rectangleall'interno di scrollView, con l' widthimpostazione su un valore maggiore della larghezza dei dati nelscrollView

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")]
        })
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.