PageViewController.swift


  1. import SwiftUI
  2. import UIKit
  3. struct PageViewController<Page: View>: UIViewControllerRepresentable {
  4. var pages: [Page]
  5. @Binding var currentPage: Int
  6. func makeCoordinator() -> Coordinator {
  7. Coordinator(self)
  8. }
  9. func makeUIViewController(context: Context) -> UIPageViewController {
  10. let pageViewController = UIPageViewController(
  11. transitionStyle: .scroll,
  12. navigationOrientation: .horizontal)
  13. pageViewController.dataSource = context.coordinator
  14. pageViewController.delegate = context.coordinator
  15. return pageViewController
  16. }
  17. func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {
  18. pageViewController.setViewControllers(
  19. [context.coordinator.controllers[currentPage]], direction: .forward, animated: true)
  20. }
  21. class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
  22. var parent: PageViewController
  23. var controllers = [UIViewController]()
  24. init(_ pageViewController: PageViewController) {
  25. parent = pageViewController
  26. controllers = parent.pages.map { UIHostingController(rootView: $0) }
  27. }
  28. func pageViewController(
  29. _ pageViewController: UIPageViewController,
  30. viewControllerBefore viewController: UIViewController) -> UIViewController?
  31. {
  32. guard let index = controllers.firstIndex(of: viewController) else {
  33. return nil
  34. }
  35. if index == 0 {
  36. return controllers.last
  37. }
  38. return controllers[index - 1]
  39. }
  40. func pageViewController(
  41. _ pageViewController: UIPageViewController,
  42. viewControllerAfter viewController: UIViewController) -> UIViewController?
  43. {
  44. guard let index = controllers.firstIndex(of: viewController) else {
  45. return nil
  46. }
  47. if index + 1 == controllers.count {
  48. return controllers.first
  49. }
  50. return controllers[index + 1]
  51. }
  52. func pageViewController(
  53. _ pageViewController: UIPageViewController,
  54. didFinishAnimating finished: Bool,
  55. previousViewControllers: [UIViewController],
  56. transitionCompleted completed: Bool) {
  57. if completed,
  58. let visibleViewController = pageViewController.viewControllers?.first,
  59. let index = controllers.firstIndex(of: visibleViewController) {
  60. parent.currentPage = index
  61. }
  62. }
  63. }
  64. }