Оскільки це найкращий результат в Google, я подумав, що поділюсь тим, що, на мою думку, є найбільш розумним способом; що полягає у використанні перехідного API iOS 7+. Я реалізував це для iOS 10 із Swift 3.
Досить просто поєднувати це з тим, як UINavigationControllerанімувати між двома контролерами перегляду, якщо ви створюєте підклас UINavigationControllerі повертаєте екземпляр класу, який відповідає UIViewControllerAnimatedTransitioningпротоколу.
Наприклад, ось мій UINavigationControllerпідклас:
class NavigationController: UINavigationController {
init() {
super.init(nibName: nil, bundle: nil)
delegate = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension NavigationController: UINavigationControllerDelegate {
public func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return NavigationControllerAnimation(operation: operation)
}
}
Ви можете бачити, що я встановлюю UINavigationControllerDelegateсобі, і в розширенні на своєму підкласі я реалізую метод, UINavigationControllerDelegateякий дозволяє повернути користувальницький контролер анімації (тобто NavigationControllerAnimation). Цей спеціальний контролер анімації замінить вам запас анімації.
Вам, напевно, цікаво, чому я передаю в операції NavigationControllerAnimationекземпляр через його ініціалізатор. Я роблю це для того, щоб в процесі NavigationControllerAnimationреалізації UIViewControllerAnimatedTransitioningпротоколу я знав, що таке операція (тобто, "push" або "pop"). Це допомагає дізнатися, якою анімацією я повинен займатися. Більшу частину часу ви хочете виконати іншу анімацію залежно від операції.
Решта - це досить стандартно. Реалізуйте дві необхідні функції в UIViewControllerAnimatedTransitioningпротоколі та анімуйте, як вам подобається:
class NavigationControllerAnimation: NSObject, UIViewControllerAnimatedTransitioning {
let operation: UINavigationControllerOperation
init(operation: UINavigationControllerOperation) {
self.operation = operation
super.init()
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.3
}
public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from),
let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) else { return }
let containerView = transitionContext.containerView
if operation == .push {
// do your animation for push
} else if operation == .pop {
// do your animation for pop
}
}
}
Важливо пам’ятати, що для кожного різного типу операцій (тобто, «push» або «pop») контролери перегляду до і від перегляду будуть різними. Коли ви працюєте з натисканням, контролером для перегляду буде той, який натискається. Коли ви перебуваєте в операції "pop", контролером view буде той, до якого переходить, а контролером з view буде той, що вискакує.
Також toконтролер подання повинен бути доданий як підпогляд containerViewпереходу в контексті переходу.
Коли ваша анімація завершиться, потрібно зателефонувати transitionContext.completeTransition(true). Якщо ви робите інтерактивний перехід, вам доведеться динамічно повертати Boolв completeTransition(didComplete: Bool)залежності від того, якщо перехід був завершений в кінці анімації.
Нарешті ( необов’язкове читання ), ви можете побачити, як я здійснив перехід, над яким працював. Цей код трохи хитріший, і я написав його досить швидко, тому я б не сказав, що це відмінний анімаційний код, але він все ще показує, як робити анімаційну частину.
Шахта була дійсно простим переходом; Я хотів наслідувати ту саму анімацію, яку зазвичай робить UINavigationController, але замість анімації "Наступна сторінка вгорі" це я хотів реалізувати анімацію старого контролера перегляду 1: 1 одночасно з новим поданням з'являється контролер. Це призводить до того, що два контролери подання виглядають так, ніби вони прив'язані один до одного.
Для операції натискання, що вимагає спочатку встановити початок toViewControllerподання виду на екрані осі x, додати його як підвид зображення containerView, анімувати його на екрані, встановивши його origin.xв нуль. У той же час, я анімую fromViewControllerпогляд, origin.xвідтворюючи його на екрані:
toViewController.view.frame = containerView.bounds.offsetBy(dx: containerView.frame.size.width, dy: 0.0)
containerView.addSubview(toViewController.view)
UIView.animate(withDuration: transitionDuration(using: transitionContext),
delay: 0,
options: [ UIViewAnimationOptions.curveEaseOut ],
animations: {
toViewController.view.frame = containerView.bounds
fromViewController.view.frame = containerView.bounds.offsetBy(dx: -containerView.frame.size.width, dy: 0)
},
completion: { (finished) in
transitionContext.completeTransition(true)
})
Операція естради - це в основному зворотна. Додайте toViewControllerяк підвид з containerView, і анімувати геть fromViewControllerвправо , як анімувати в toViewControllerзліва:
containerView.addSubview(toViewController.view)
UIView.animate(withDuration: transitionDuration(using: transitionContext),
delay: 0,
options: [ UIViewAnimationOptions.curveEaseOut ],
animations: {
fromViewController.view.frame = containerView.bounds.offsetBy(dx: containerView.frame.width, dy: 0)
toViewController.view.frame = containerView.bounds
},
completion: { (finished) in
transitionContext.completeTransition(true)
})
Ось суть із усім швидким файлом:
https://gist.github.com/alanzeino/603293f9da5cd0b7f6b60dc20bc766be