|
final class NavigationPopTransitionController: UIPercentDrivenInteractiveTransition { |
|
|
|
let navigationController: UINavigationController |
|
|
|
private lazy var interactivePopGestureRecognizer = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(handle)) |
|
|
|
var ifInteractive: Self? { |
|
interactivePopGestureRecognizer.state == .began ? self : nil |
|
} |
|
|
|
init(navigationController: UINavigationController) { |
|
self.navigationController = navigationController |
|
super.init() |
|
interactivePopGestureRecognizer.edges = .left |
|
interactivePopGestureRecognizer.delegate = self |
|
navigationController.view.addGestureRecognizer(interactivePopGestureRecognizer) |
|
} |
|
|
|
} |
|
|
|
private extension NavigationPopTransitionController { |
|
|
|
@objc func handle(_ recognizer: UIScreenEdgePanGestureRecognizer) { |
|
guard let view = recognizer.view else { return } |
|
let translation = recognizer.translation(in: view) |
|
let velocity = recognizer.velocity(in: view) |
|
let width = view.bounds.width |
|
let progress = translation.x / width |
|
switch recognizer.state { |
|
case .began: |
|
navigationController.popViewController(animated: true) |
|
case .changed: |
|
update(min(progress, 0.999)) |
|
case .ended: |
|
if progress >= 0.5 || velocity.x > 0 { |
|
completionSpeed = duration * velocity.x / width |
|
finish() |
|
} else { |
|
cancel() |
|
} |
|
case .cancelled: |
|
cancel() |
|
default: |
|
break |
|
} |
|
} |
|
|
|
} |
|
|
|
extension NavigationPopTransitionController: UIGestureRecognizerDelegate { |
|
|
|
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { |
|
// Only allowed if no active transition. |
|
return navigationController.transitionCoordinator == nil |
|
} |
|
|
|
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool { |
|
// Don't muck up horizontal scrolling. |
|
otherGestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer.view is UIScrollView |
|
} |
|
|
|
} |
|
|
|
extension Foo: UINavigationControllerDelegate { |
|
|
|
lazy var navigationPopTransition = NavigationPopTransitionController(...) |
|
|
|
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { |
|
MyAwesomeAnimator(for: operation) |
|
} |
|
|
|
func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { |
|
navigationPopTransition?.ifInteractive |
|
} |
|
|
|
} |