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

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

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

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

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")]
        })
    }
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.