Reputation: 5354
Im trying to detect when the user is scrolling and he arrives near to the bottom so I can load my next batch of data. I have implemented scrollViewDidScroll(_ scrollView: UIScrollView)
but nothing happens. The only time it gets trigger is when I pull up the screen after I'm at the bottom. So I need to go past the bottom in order for it to be triggered.
What am I doing wrong here ?
import SwiftUI
struct RequestsListView: View {
@ObservedObject var requestsViewModel: RequestsViewModel
var body: some View {
List {
ForEach(requestsViewModel.requests) { (request: Request) in
if let item = request.item {
RequestRowView(
requestViewModel: RequestViewModel(request: request),
itemViewModel: ItemViewModel(item: item)
)
.onAppear() {
if let index = requestsViewModel.requests.firstIndex(where: {$0.id == request.id}), index == 0 {
print("load more")
//requestsViewModel.load()
}
}
}
}
}
.onAppear() {
print("initialise")
if !requestsViewModel.loaded {
requestsViewModel.load()
}
}
}
}
class RequestsViewModel: ObservableObject {
@Published var requests = [Request]()
@Published var error = ""
@Published var loaded = false
var firestoreService: FirestoreService = FirestoreService()
var uid = Auth.auth().currentUser?.uid
var lastDocumentSnapshot: DocumentSnapshot?
var field: String
let limit = 6
init(field: String) {
self.field = field
}
func load() {
guard let uid = self.uid else { return }
var query: Query!
let itemsCollection: Query = Firestore.firestore().collection("requests").whereField(field, isEqualTo: uid)
//everytime you need more data fetched and on database updates to your snapshot this will be triggered
// ver order
if let nextStartingSnap = self.lastDocumentSnapshot {
query = itemsCollection.start(afterDocument: nextStartingSnap).limit(to: limit)
} else {
query = itemsCollection.limit(to: limit)
}
query.addSnapshotListener { (snapshot, error) in
self.loaded = true
guard let snapshot = snapshot else {
self.error = error!.localizedDescription
return
}
guard let lastSnapshot = snapshot.documents.last else {
// The collection is empty.
return
}
self.lastDocumentSnapshot = lastSnapshot
snapshot.documentChanges.forEach { (documentChange) in
if (documentChange.type == .added) {
var request = Request(document: documentChange.document)
self.firestoreService.fetchDocument(documentReference: request.itemReference) { (result: Result<Item, Error>) in
switch result {
case .success(let item):
request.item = item
self.requests.append(request)
case .failure(let error):
self.error = error.localizedDescription
}
}
}
}
}
}
}
Upvotes: 1
Views: 3238
Reputation: 454
I did this via finding out whether the object displayed is the last element in list, then by calling fetchMore function
//EmployeeViewModel
class EmployeeViewModel: ObservableObject {
@Published var employees : [Employee] = []
func initialize() {
self.employees = [Employee(name: "A", id: "100"),
Employee(name: "B", id: "101"),
Employee(name: "C", id: "102"),
Employee(name: "D", id: "103"),
Employee(name: "E", id: "104"),
Employee(name: "F", id: "105"),
Employee(name: "G", id: "106"),
Employee(name: "H", id: "107"),
Employee(name: "I", id: "108"),
Employee(name: "J", id: "109"),
Employee(name: "K", id: "110"),
Employee(name: "L", id: "112"),
Employee(name: "M", id: "113"),
Employee(name: "N", id: "114"),
Employee(name: "O", id: "115"),
Employee(name: "P", id: "116"),
Employee(name: "Q", id: "117"),
Employee(name: "R", id: "118"),
Employee(name: "S", id: "119"),
Employee(name: "T", id: "120"),
Employee(name: "U", id: "121"),
Employee(name: "V", id: "122"),
Employee(name: "W", id: "123")]
}
//fetch more employees inside viewmodel
func fetchMoreEmployees(employee: Employee) {
if let index = self.employees.firstIndex(where: {$0.id == employee.id}) {
if index == self.employees.count - 1 {
print("Item: \(employee.name) - Reached bottom of list ")
} else if index == 0 {
print("Item: \(employee.name) - Reached top of list")
}
}
}
}
struct EmployeeView: View {
@ObservedObject var vm = EmployeeViewModel()
var body: some View {
NavigationView {
List {
ForEach(self.vm.employees) { employee in
EmployeeCellView(vm: self.vm, employee: employee)
}.listRowBackground(Color.white)
}.onAppear(perform: initialize)
.navigationBarTitle("Users", displayMode: .inline)
}
}
func initialize() {
self.vm.initialize()
}
}
struct EmployeeCellView: View {
@ObservedObject var vm: EmployeeViewModel
let employee: Employee
var body: some View {
Text("\(employee.name)").onAppear(perform: fetchMore)
}
func fetchMore() {
self.vm.fetchMoreEmployees(employee: self.employee)
}
}
Add this fetchMoreEmployees(employee: Employee)
function inside your ViewModel and call this function in .onAppear()
of your cell shown above.
Upvotes: 1