O SwiftUI ScrollView não está sendo atualizado?

10

Objetivo

Obter dados para exibição em um scrollView

resultado esperado

dados mostrados no scrollview

Resultado atual

uma visão em branco

Alternativa

use List, mas não é flexível (não é possível remover separadores, não pode ter várias colunas)

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")]
        })
    }
}
youjin
fonte
Testei isso no Xcode 11.1, iOS 13.1, Swift 5 e estou obtendo o resultado esperado (embora a exibição de rolagem esteja no topo e não no centro).
sfung3
Você também não precisa da palavrareturn
sfung3 13/11/19
interessante, eu estou no Xcode 11.2, iOS 13.2, Swift 5
youjin
Sim, eu tinha uma printdeclaração antes, daí areturn
youjin
Vou atualizar para o Xcode 11.2 e ver se consigo reproduzir isso. Pode demorar um pouco, mas atualizarei você com minhas descobertas.
sfung3

Respostas:

10

Uma maneira não tão hacky de contornar esse problema é colocar o ScrollView em uma instrução IF que verifica se a matriz está vazia

if !self.array.isEmpty{
     ScrollView(.vertical) {
          ForEach(array) { o in
               Text(o.id)
          }
     }
}
paulaysabellemedina
fonte
Esta solução alternativa é perfeita, obrigado!
Hendrik
1

O comportamento esperado ocorre, Xcode 11.1mas não acontece.Xcode 11.2.1

Eu adicionei um framemodificador ao ScrollViewqual fazer 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")]
        })
    }
}
sfung3
fonte
Infelizmente não é possível fazê-lo funcionar no iOS 13.2 no Simulator
youjin
1

Eu descobri que ele funciona (Xcode 11.2) como esperado se o estado foi inicializado com algum valor, e não uma matriz vazia. Nesse caso, a atualização funciona corretamente e o estado inicial não tem efeito.

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
fonte
que funciona para o caso simples, no meu caso eu tenho uma chamada de rede em onAppear, então inicializar o scrollView com dados fictícios pode ser problemático
Youjin
correto, mas essa situação pode ser tratada logicamente no código, porque o objeto inicial pode ser um stub de fácil detecção para mostrar condicionalmente algo como 'loading' etc. para mim isso foi o suficiente ... vale a pena compartilhar.
Asperi
1

Uma solução hacky que encontrei é adicionar um "invisível" Rectangledentro do scrollView, com o widthconjunto com um valor maior que a largura dos dados noscrollView

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
fonte