项目作者: crelies

项目描述 :
Swift package providing extensions of RandomAccessCollection to support List pagination in SwiftUI
高级语言: Swift
项目地址: git://github.com/crelies/ListPagination.git
创建时间: 2019-08-15T07:38:31Z
项目社区:https://github.com/crelies/ListPagination

开源协议:MIT License

下载


ListPagination

Swift 5.3
Platform
License

This Swift package provides extensions of RandomAccessCollection which help you add pagination support to your SwiftUI List view. It is already integrated in my AdvancedList view (Wrapper around SwiftUI’s List view).

Installation

Add this Swift package in Xcode using its Github repository url. (File > Swift Packages > Add Package Dependency…)

How to use

You can add pagination with two different approaches to your List: Last item approach and Threshold item approach.

That’s way this package adds two functions to RandomAccessCollection:

isLastItem

Use this function to check if the item in the current List item iteration is the last item of your collection.

isThresholdItem

With this function you can find out if the item of the current List item iteration is the item at your defined threshold.
Pass an offset (distance to the last item) to the function so the threshold item can be determined.

Example

Both example code snippets below require a simple extension of String:

  1. /*
  2. If you want to display an array of strings
  3. in the List view you have to specify a key path,
  4. so each string can be uniquely identified.
  5. With this extension you don't have to do that anymore.
  6. */
  7. extension String: Identifiable {
  8. public var id: String {
  9. return self
  10. }
  11. }

Last item approach

  1. struct ListPaginationExampleView: View {
  2. @State private var items: [String] = Array(0...24).map { "Item \($0)" }
  3. @State private var isLoading: Bool = false
  4. @State private var page: Int = 0
  5. private let pageSize: Int = 25
  6. var body: some View {
  7. NavigationView {
  8. List(items) { item in
  9. VStack(alignment: .leading) {
  10. Text(item)
  11. if self.isLoading && self.items.isLastItem(item) {
  12. Divider()
  13. Text("Loading ...")
  14. .padding(.vertical)
  15. }
  16. }.onAppear {
  17. self.listItemAppears(item)
  18. }
  19. }
  20. .navigationBarTitle("List of items")
  21. .navigationBarItems(trailing: Text("Page index: \(page)"))
  22. }
  23. }
  24. }
  25. extension ListPaginationExampleView {
  26. private func listItemAppears<Item: Identifiable>(_ item: Item) {
  27. if items.isLastItem(item) {
  28. isLoading = true
  29. /*
  30. Simulated async behaviour:
  31. Creates items for the next page and
  32. appends them to the list after a short delay
  33. */
  34. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) {
  35. self.page += 1
  36. let moreItems = self.getMoreItems(forPage: self.page, pageSize: self.pageSize)
  37. self.items.append(contentsOf: moreItems)
  38. self.isLoading = false
  39. }
  40. }
  41. }
  42. }

Threshold item approach

  1. struct ListPaginationThresholdExampleView: View {
  2. @State private var items: [String] = Array(0...24).map { "Item \($0)" }
  3. @State private var isLoading: Bool = false
  4. @State private var page: Int = 0
  5. private let pageSize: Int = 25
  6. private let offset: Int = 10
  7. var body: some View {
  8. NavigationView {
  9. List(items) { item in
  10. VStack(alignment: .leading) {
  11. Text(item)
  12. if self.isLoading && self.items.isLastItem(item) {
  13. Divider()
  14. Text("Loading ...")
  15. .padding(.vertical)
  16. }
  17. }.onAppear {
  18. self.listItemAppears(item)
  19. }
  20. }
  21. .navigationBarTitle("List of items")
  22. .navigationBarItems(trailing: Text("Page index: \(page)"))
  23. }
  24. }
  25. }
  26. extension ListPaginationThresholdExampleView {
  27. private func listItemAppears<Item: Identifiable>(_ item: Item) {
  28. if items.isThresholdItem(offset: offset,
  29. item: item) {
  30. isLoading = true
  31. /*
  32. Simulated async behaviour:
  33. Creates items for the next page and
  34. appends them to the list after a short delay
  35. */
  36. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.5) {
  37. self.page += 1
  38. let moreItems = self.getMoreItems(forPage: self.page, pageSize: self.pageSize)
  39. self.items.append(contentsOf: moreItems)
  40. self.isLoading = false
  41. }
  42. }
  43. }
  44. }