Is there any way to make a paged ScrollView in SwiftUI?

前端 未结 7 1335
轻奢々
轻奢々 2021-02-03 15:02

I\'ve been looking through the docs with each beta but haven\'t seen a way to make a traditional paged ScrollView. I\'m not familiar with AppKit so I am wondering if this doesn\

7条回答
  •  故里飘歌
    2021-02-03 15:27

    You can simply track state using .onAppear() to load your next page.

    struct YourListView : View {
    
        @ObservedObject var viewModel = YourViewModel()
    
        let numPerPage = 50
    
        var body: some View {
            NavigationView {
                List(viewModel.items) { item in
                    NavigationLink(destination: DetailView(item: item)) {
                        ItemRow(item: item)
                        .onAppear {
                            if self.shouldLoadNextPage(currentItem: item) {
                                self.viewModel.fetchItems(limitPerPage: self.numPerPage)
                            }
                        }
                    }
                }
                .navigationBarTitle(Text("Items"))
                .onAppear {
                    guard self.viewModel.items.isEmpty else { return }
                    self.viewModel.fetchItems(limitPerPage: self.numPerPage)
                }
            }
        }
    
        private func shouldLoadNextPage(currentItem item: Item) -> Bool {
            let currentIndex = self.viewModel.items.firstIndex(where: { $0.id == item.id } )
            let lastIndex = self.viewModel.items.count - 1
            let offset = 5 //Load next page when 5 from bottom, adjust to meet needs
            return currentIndex == lastIndex - offset
        }
    }
    
    class YourViewModel: ObservableObject {
        @Published private(set) items = [Item]()
        // add whatever tracking you need for your paged API like next/previous and count
        private(set) var fetching = false
        private(set) var next: String?
        private(set) var count = 0
    
    
        func fetchItems(limitPerPage: Int = 30, completion: (([Item]?) -> Void)? = nil) {
            // Do your stuff here based on the API rules for paging like determining the URL etc...
            if items.count == 0 || items.count < count {
                let urlString = next ?? "https://somePagedAPI?limit=/(limitPerPage)"
                fetchNextItems(url: urlString, completion: completion)
            } else {
                completion?(pokemon)
            }
    
        }
    
        private func fetchNextItems(url: String, completion: (([Item]?) -> Void)?) {
            guard !fetching else { return }
            fetching = true
            Networking.fetchItems(url: url) { [weak self] (result) in
                DispatchQueue.main.async { [weak self] in
                    self?.fetching = false
                    switch result {
                    case .success(let response):
                        if let count = response.count {
                            self?.count = count
                        }
                        if let newItems = response.results {
                            self?.items += newItems
                        }
                        self?.next = response.next
                    case .failure(let error):
                        // Error state tracking not implemented but would go here...
                        os_log("Error fetching data: %@", error.localizedDescription)
                    }
                }
            }
        }
    }
    

    Modify to fit whatever API you are calling and handle errors based on your app architecture.

提交回复
热议问题