Оскільки це найкращий результат в 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