Last active
April 4, 2021 02:42
-
-
Save gromwel/63007f2e444d9b74422cf480284ed6d4 to your computer and use it in GitHub Desktop.
Custom navigation controller push pop transition animation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
final class VC1: UIViewController { | |
private lazy var gr = UITapGestureRecognizer(target: self, action: #selector(self.tap)) | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
self.view.backgroundColor = .systemPink | |
self.view.addGestureRecognizer(self.gr) | |
self.navigationController?.delegate = self | |
} | |
@objc private func tap() { | |
let vc = UIViewController() | |
vc.view.backgroundColor = .systemTeal | |
self.navigationController?.pushViewController(vc, animated: true) | |
} | |
} | |
extension VC1: UINavigationControllerDelegate { | |
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { | |
switch operation { | |
case .none: break | |
case .push: return PushTransitioning() | |
case .pop: return PopTransitioning() | |
@unknown default: break | |
} | |
return nil | |
} | |
} | |
fileprivate class PushTransitioning: NSObject, UIViewControllerAnimatedTransitioning { | |
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 0.3 } | |
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { | |
guard let to = transitionContext.viewController(forKey: .to) else { return } | |
// Добавляем вьюху | |
let container = transitionContext.containerView | |
container.addSubview(to.view) | |
// Настраиваем положение | |
let frame = transitionContext.finalFrame(for: to) | |
to.view.transform = CGAffineTransform(scaleX: 0.9, y: 0.9) | |
to.view.frame.origin.x = frame.width | |
// Анимируем | |
UIView.animateKeyframes( | |
withDuration: self.transitionDuration(using: transitionContext), | |
delay: 0.0, | |
options: [] | |
){ | |
UIView.addKeyframe( | |
withRelativeStartTime: 0.0, | |
relativeDuration: 0.9 | |
) { | |
to.view.center.x = frame.width / 2 | |
} | |
UIView.addKeyframe( | |
withRelativeStartTime: 0.9, | |
relativeDuration: 0.1 | |
) { | |
to.view.transform = .identity | |
} | |
} completion: { _ in | |
transitionContext.completeTransition(!transitionContext.transitionWasCancelled) | |
} | |
} | |
} | |
fileprivate class PopTransitioning: NSObject, UIViewControllerAnimatedTransitioning { | |
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 0.3 } | |
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { | |
guard | |
let to = transitionContext.viewController(forKey: .to), | |
let from = transitionContext.viewController(forKey: .from) | |
else { return } | |
// Добавляем вьюху | |
let container = transitionContext.containerView | |
container.insertSubview(to.view, belowSubview: from.view) | |
// Положение | |
let width = transitionContext.initialFrame(for: from).width | |
// Анимируем | |
UIView.animateKeyframes( | |
withDuration: self.transitionDuration(using: transitionContext), | |
delay: 0.0, | |
options: [], | |
animations: { | |
UIView.addKeyframe( | |
withRelativeStartTime: 0.0, | |
relativeDuration: 0.1, | |
animations: { | |
from.view.transform = CGAffineTransform(scaleX: 0.9, y: 0.9) | |
} | |
) | |
UIView.addKeyframe( | |
withRelativeStartTime: 0.1, | |
relativeDuration: 0.9, | |
animations: { | |
from.view.frame.origin.x = width | |
} | |
) | |
}, | |
completion: { _ in | |
transitionContext.completeTransition(!transitionContext.transitionWasCancelled) | |
} | |
) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment