Skip to content

Instantly share code, notes, and snippets.

@gromwel
Last active April 4, 2021 02:42
Show Gist options
  • Save gromwel/63007f2e444d9b74422cf480284ed6d4 to your computer and use it in GitHub Desktop.
Save gromwel/63007f2e444d9b74422cf480284ed6d4 to your computer and use it in GitHub Desktop.
Custom navigation controller push pop transition animation
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