diff --git a/Tusker/Screens/Utilities/SegmentedPageViewController.swift b/Tusker/Screens/Utilities/SegmentedPageViewController.swift index 30c1f6d8..7510eef4 100644 --- a/Tusker/Screens/Utilities/SegmentedPageViewController.swift +++ b/Tusker/Screens/Utilities/SegmentedPageViewController.swift @@ -12,8 +12,8 @@ protocol SegmentedPageViewControllerPage: Hashable { var segmentedControlTitle: String { get } } -class SegmentedPageViewController: UIPageViewController, UIPageViewControllerDelegate, TabbedPageViewController { - +class SegmentedPageViewController: UIViewController, UIPageViewControllerDelegate, TabbedPageViewController { + private(set) var pages: [Page]! private let pageProvider: (Page) -> UIViewController private var pageControllers = [Page: UIViewController]() @@ -23,12 +23,10 @@ class SegmentedPageViewController: UIPage var currentIndex: Int! { pages.firstIndex(of: currentPage) } - var currentViewController: UIViewController! { - viewControllers?.first - } + var currentViewController: UIViewController! let segmentedControl = ScrollingSegmentedControl() - + init(pages: [Page], pageProvider: @escaping (Page) -> UIViewController) { precondition(!pages.isEmpty) @@ -37,7 +35,7 @@ class SegmentedPageViewController: 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: 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: 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: 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 {