【问题标题】:SwiftUI UIScrollView Detect when user scrolls near the bottomSwiftUI UIScrollView 当用户滚动到底部附近时检测
【发布时间】:2020-11-01 19:59:06
【问题描述】:

我试图检测用户何时滚动并且他到达底部附近,以便我可以加载下一批数据。我已经实现了scrollViewDidScroll(_ scrollView: UIScrollView),但没有任何反应。它触发的唯一一次是当我在底部后拉起屏幕时。所以我需要越过底部才能触发它。

我在这里做错了什么?

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

【问题讨论】:

    标签: ios swift uiscrollview swiftui swift5


    【解决方案1】:

    我通过找出显示的对象是否是列表中的最后一个元素,然后调用 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)
        }
    }
    

    在您的 ViewModel 中添加此 fetchMoreEmployees(employee: Employee) 函数,并在上面显示的单元格的 .onAppear() 中调用此函数。

    【讨论】:

    • 当我滚动到顶部时它工作正常,但我需要相反,当它滚动到底部时。知道如何实现吗?
    • 所以我希望在滚动到列表末尾时触发它
    • @RexhinHoxha。我已经将它用于我的聊天页面,所以当我滚动到顶部时我需要分页逻辑。另外,根据时间对我的数组进行了排序。您只需更改那里的数组逻辑,就像我猜 index == 0 一样,请尝试一下。
    • @RexhinHoxha 在数组中找出行对象的索引并进行比较。检查它是否是最后一个元素。
    • @RexhinHoxha 请显示用于构建列表的代码,以便我为您提供帮助。我也编辑了我的答案,请检查
    猜你喜欢
    • 2012-09-25
    • 2020-10-11
    • 1970-01-01
    • 2012-09-21
    • 2012-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多