SwiftUI ScrollView не обновляется?


10

Цель

Получить данные для отображения в scrollView

ожидаемый результат

данные отображаются в виде прокрутки

Фактический результат

пустой вид

альтернатива

использовать List, но он не гибкий (не может удалить разделители, не может иметь несколько столбцов)

Код

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

Я протестировал это на Xcode 11.1, iOS 13.1, Swift 5 и получаю ожидаемый результат (хотя вид прокрутки сверху, а не по центру).
sfung3

Вам также не нужно ключевое словоreturn
sfung3

Интересно, я на Xcode 11.2, iOS 13.2, Swift 5
youjin

да, у меня было printзаявление раньше, следовательноreturn
youjin

Я обновлю до Xcode 11.2 и посмотрю, смогу ли я воспроизвести это. Это может занять некоторое время, но я сообщу вам о своих выводах.
sfung3

Ответы:


10

Не очень удачный способ обойти эту проблему - заключить ScrollView в оператор IF, который проверяет, является ли массив пустым

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

Этот обходной путь идеален, спасибо!
Хендрик

1

Ожидаемое поведение происходит, Xcode 11.1но не включаетсяXcode 11.2.1

Я добавил frameмодификатор, ScrollViewкоторый делает ScrollViewпоявление

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

К сожалению, не удалось заставить его работать на iOS 13.2 на симуляторе
youjin

1

Я обнаружил, что это работает (Xcode 11.2), как и ожидалось, если состояние инициализируется некоторым значением, а не пустым массивом. В этом случае обновление работает корректно и исходное состояние не действует.

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

это работает для простого случая, в моем случае у меня есть сетевой вызов onAppear, поэтому инициализация scrollView с фиктивными данными может быть проблематичной
youjin

правильно, но эта ситуация может быть обработана логически в коде, потому что исходный объект может быть некоторой легко обнаруживаемой заглушкой, чтобы условно показать что-то вроде «загрузки» и т. д. для меня этого было достаточно ... поэтому стоит поделиться.
Аспери

1

Один хакерский обходной путь, который я нашел, состоит в добавлении «невидимого» Rectangleвнутри scrollView с widthустановленным значением, превышающим ширину данных вscrollView

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")]
        })
    }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.