Don't use UIPageViewController for SegmentedPageViewController

This commit is contained in:
Shadowfacts 2023-01-16 16:27:32 -05:00
parent baa9dfe0f1
commit e4f3735c9f
1 changed files with 44 additions and 11 deletions

View File

@ -12,8 +12,8 @@ protocol SegmentedPageViewControllerPage: Hashable {
var segmentedControlTitle: String { get }
}
class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPageViewController, UIPageViewControllerDelegate, TabbedPageViewController {
class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIViewController, UIPageViewControllerDelegate, TabbedPageViewController {
private(set) var pages: [Page]!
private let pageProvider: (Page) -> UIViewController
private var pageControllers = [Page: UIViewController]()
@ -23,12 +23,10 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPage
var currentIndex: Int! {
pages.firstIndex(of: currentPage)
}
var currentViewController: UIViewController! {
viewControllers?.first
}
var currentViewController: UIViewController!
let segmentedControl = ScrollingSegmentedControl<Page>()
init(pages: [Page], pageProvider: @escaping (Page) -> UIViewController) {
precondition(!pages.isEmpty)
@ -37,7 +35,7 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPage
initialPage = pages.first!
currentPage = pages.first!
super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
super.init(nibName: nil, bundle: nil)
setPages(pages, animated: false)
@ -104,12 +102,12 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPage
initialPage = page
return
}
let direction: UIPageViewController.NavigationDirection
let direction: AnimationMode
if let prevIndex = currentIndex {
let index = pages.firstIndex(of: page)!
direction = index - prevIndex > 0 ? .forward : .reverse
} else {
direction = .forward
direction = .none
}
currentPage = page
@ -121,12 +119,40 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPage
pageControllers[page] = newController
}
setViewControllers([newController], direction: direction, animated: animated)
setViewController(newController, animated: animated ? direction : .none)
navigationItem.title = newController.title
segmentedControl.setSelectedOption(page, animated: animated)
}
private func setViewController(_ newViewController: UIViewController, animated: AnimationMode) {
guard let currentViewController,
animated != .none else {
currentViewController?.removeViewAndController()
newViewController.view.translatesAutoresizingMaskIntoConstraints = false
embedChild(newViewController)
self.currentViewController = newViewController
return
}
guard currentViewController !== newViewController else {
return
}
self.currentViewController = newViewController
newViewController.view.translatesAutoresizingMaskIntoConstraints = false
embedChild(newViewController)
let direction: CGFloat = animated == .forward ? 1 : -1
newViewController.view.transform = CGAffineTransform(translationX: direction * view.bounds.width, y: 0)
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UISpringTimingParameters(dampingRatio: 1, initialVelocity: .zero))
animator.addAnimations {
newViewController.view.transform = .identity
currentViewController.view.transform = CGAffineTransform(translationX: -1 * direction * self.view.bounds.width, y: 0)
}
animator.addCompletion { _ in
currentViewController.removeViewAndController()
}
animator.startAnimation()
}
// MARK: TabbedPageViewController
func selectNextPage() {
@ -138,7 +164,14 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPage
guard currentIndex > 0 else { return }
selectPage(pages[currentIndex - 1], animated: true)
}
}
extension SegmentedPageViewController {
enum AnimationMode: Equatable {
case none
case forward
case reverse
}
}
extension SegmentedPageViewController: TabBarScrollableViewController {