Загрузите больше функциональности, используя SwiftUI

Я использовал ScrollView с HStack, теперь мне нужно загрузить больше данных, когда пользователь наконец достиг прокрутки.

var items: [Landmark]

Я использовал множество предметов, которые я добавляю в HStack с помощью ForEach

ScrollView(showsHorizontalIndicator: false) {
    HStack(alignment: .top, spacing: 0) {
        ForEach(self.items) { landmark in
            CategoryItem(landmark: landmark)
        }
    }
}

Каково наилучшее из возможных решений для управления большей загрузкой в SwiftUI без использования пользовательских действий, таких как кнопка loadmore.

2 ответа

Для этого лучше использовать ForEach и List

struct ContentView : View {
    @State var textfieldText: String = "String "
    private let chunkSize = 10
    @State var range: Range<Int> = 0..<1

    var body: some View {
        List {
            ForEach(range) { number in
                Text("\(self.textfieldText) \(number)")
            }
            Button(action: loadMore) {
                Text("Load more")
            }
        }
    }

    func loadMore() {
        print("Load more...")
        self.range = 0..<self.range.upperBound + self.chunkSize
    }
}

В этом примере каждый раз, когда вы нажимаете load, это увеличивает диапазон свойств State. То же самое вы можете сделать для BindableObject. Если вы хотите сделать это автоматически, вероятно, вам следует прочитать о PullDownButton(я не уверен, работает ли он для PullUp)

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

var body: some View {
        List {
            ForEach(range) { number in
                Text("\(self.textfieldText) \(number)")
            }
            Button(action: loadMore) {
                Text("")
                }
                .onAppear {
                    DispatchQueue.global(qos: .background).asyncAfter(deadline: DispatchTime(uptimeNanoseconds: 10)) {
                        self.loadMore()
                    }
            }
        }
    }

Имейте в виду, что отправка необходима, потому что без нее у вас будет ошибка "Обновление табличного представления при обновлении табличного представления). Возможно, вы можете использовать другой асинхронный способ обновления данных.

Если вы хотите продолжать использовать List сDataвместоRange, вы можете реализовать следующий скрипт:

      struct ContentView: View {

    @State var items: [Landmark]

    var body: some View {
        List {
            ForEach(self.items) { landmark in
                CategoryItem(landmark: landmark)
                   .onAppear {
                      checkForMore(landmark)
                   }
            }
        }
    }

    func checkForMore(_ item: LandMark) {
       guard let item = item else { return }

       let thresholdIndex = items.index(items.endIndex, offsetBy: -5)
        if items.firstIndex(where: { $0.id == item.id }) == thresholdIndex {
           // function to request more data
            getMoreLandMarks()
        }
    }
}

Вероятно, вам следует работать в ViewModel и отделить логику от пользовательского интерфейса.

Кредиты Донни Уолсу: полный пример

Другие вопросы по тегам