Reputation: 8680
i have used ScrollView with HStack, now i need to load more data when user reached scrolling at last.
var items: [Landmark]
i have used array of items which i am appeding in HStack
using ForEach
ScrollView(showsHorizontalIndicator: false) {
HStack(alignment: .top, spacing: 0) {
ForEach(self.items) { landmark in
CategoryItem(landmark: landmark)
}
}
}
What is the best possible solution to manage load more in SwiftUI without using custom action like loadmore button.
Upvotes: 11
Views: 10747
Reputation: 482
If you want to keep using List with Data
instead of Range
, you could implement the next script:
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()
}
}
}
You should work in a ViewModel and separate the logic from the UI.
Credits to Donny Wals: Complete example
Upvotes: 2
Reputation: 2811
It's better to use ForEach and List for this purpose
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
}
}
In this example each time you press load more it increases range of State property. The same you can do for BindableObject. If you want to do it automatically probably you should read about PullDownButton(I'm not sure if it works for PullUp)
UPD: As an option you can download new items by using onAppear modifier on the last cell(it is a static button in this example)
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()
}
}
}
}
Keep in mind, that dispatch is necessary, because without it you will have an error saying "Updating table view while table view is updating). Possible you may using another async way to update the data
Upvotes: 11