SwiftUI UIScrollView Обнаруживает, когда пользователь прокручивает в нижней части - PullRequest
1 голос
/ 12 июля 2020

Я пытаюсь определить, когда пользователь прокручивает, и он подходит ближе к низу, чтобы я мог загрузить свой следующий пакет данных. Я реализовал scrollViewDidScroll(_ scrollView: UIScrollView), но ничего не происходит. Единственный раз, когда он срабатывает, - это когда я поднимаю экран после того, как оказываюсь внизу. Поэтому мне нужно go пройти за дно, чтобы он сработал.

Что я здесь делаю не так?

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

1 Ответ

1 голос
/ 13 июля 2020

Я сделал это, выяснив, является ли отображаемый объект последним элементом в списке, а затем вызвав функцию fetchMore

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

Добавьте эту fetchMoreEmployees(employee: Employee) функцию внутри вашей ViewModel и вызовите эту функцию в .onAppear() ячейки, показанной выше.

...