¿SwiftUI ScrollView no se actualiza?


10

Objetivo

Obtener datos para mostrar en un scrollView

Resultado Esperado

datos mostrados en scrollview

Resultado actual

una vista en blanco

Alternativa

uso List, pero no es flexible (no puede eliminar separadores, no puede tener varias columnas)

Código

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

Probé esto en Xcode 11.1, iOS 13.1, Swift 5 y obtengo el resultado esperado (aunque la vista de desplazamiento está en la parte superior en lugar de en el centro).
sfung3

Tampoco necesita la palabra clavereturn
sfung3

interesante, estoy en Xcode 11.2, iOS 13.2, Swift 5
youjin el

Sí, tenía una printdeclaración antes, de ahí elreturn
youjin

Actualizaré a Xcode 11.2 y veré si puedo reproducir esto. Puede llevar un tiempo, pero lo actualizaré sobre mis hallazgos.
sfung3

Respuestas:


10

Una forma no tan maliciosa de solucionar este problema es incluir el ScrollView en una instrucción IF que verifique si la matriz está vacía

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

Esta solución es perfecta, ¡gracias!
Hendrik

1

El comportamiento esperado ocurre en Xcode 11.1pero no enXcode 11.2.1

Agregué un framemodificador al ScrollViewque hace ScrollViewaparecer

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

Desafortunadamente no puedo hacerlo funcionar en iOS 13.2 en Simulator
youjin

1

Descubrí que funciona (Xcode 11.2) como se esperaba si el estado se inicializa con algún valor, no con una matriz vacía. En este caso, la actualización funciona correctamente y el estado inicial no tiene ningún efecto.

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

eso funciona para el caso simple, en mi caso tengo una llamada de red onAppear, por lo que inicializar scrollView con datos ficticios puede ser problemático
youjin

correcto, pero esta situación se puede manejar lógicamente en el código, porque el objeto inicial puede ser un trozo fácil de detectar para mostrar condicionalmente algo como 'cargar', etc. para mí esto fue suficiente ... así que vale la pena compartirlo.
Asperi

1

Una solución alternativa que he encontrado es agregar un "invisible" Rectangledentro de scrollView, con el widthconjunto a un valor mayor que el ancho de los datos en elscrollView

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")]
        })
    }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.