Como este es el mejor resultado en Google, pensé en compartir lo que creo que es la forma más sensata; que es usar la API de transición de iOS 7+. Implementé esto para iOS 10 con Swift 3.
Es bastante simple combinar esto con la forma en que se UINavigationControlleranima entre dos controladores de vista si crea una subclase de UINavigationControllery devuelve una instancia de una clase que se ajusta al UIViewControllerAnimatedTransitioningprotocolo.
Por ejemplo, aquí está mi UINavigationControllersubclase:
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)
}
}
Puede ver que configuré el UINavigationControllerDelegatemismo y, en una extensión de mi subclase, implemento el método UINavigationControllerDelegateque le permite devolver un controlador de animación personalizado (es decir, NavigationControllerAnimation). Este controlador de animación personalizado reemplazará la animación original por usted.
Probablemente se esté preguntando por qué paso la operación a la NavigationControllerAnimationinstancia a través de su inicializador. Hago esto para que en NavigationControllerAnimationla implementación de laUIViewControllerAnimatedTransitioning protocolo sepa cuál es la operación (es decir, 'push' o 'pop'). Esto ayuda a saber qué tipo de animación debo hacer. La mayoría de las veces, desea realizar una animación diferente según la operación.
El resto es bastante estándar. Implemente las dos funciones requeridas en el UIViewControllerAnimatedTransitioningprotocolo y anime como quiera:
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
}
}
}
Es importante recordar que para cada tipo diferente de operación (es decir, 'push' o 'pop'), los controladores de vista de ida y vuelta serán diferentes. Cuando está en una operación de inserción, el controlador para ver será el que se está presionando. Cuando está en una operación emergente, el controlador de vista será el que se está haciendo la transición, y el controlador de vista será el que se está haciendo estallar.
Además, el tocontrolador de vista debe agregarse como una subvista del containerViewcontexto de transición.
Cuando finalice su animación, debe llamar transitionContext.completeTransition(true). Si está haciendo una transición interactiva, tendrá que devolver dinámicamente un Boola completeTransition(didComplete: Bool), dependiendo de si la transición se completa al final de la animación.
Finalmente ( lectura opcional ), es posible que desee ver cómo hice la transición en la que estaba trabajando. Este código es un poco más hacky y lo escribí bastante rápido, por lo que no diría que es un gran código de animación, pero aún muestra cómo hacer la parte de animación.
La mía fue una transición realmente simple; Quería imitar la misma animación que normalmente hace UINavigationController, pero en lugar de la animación 'siguiente página sobre la parte superior', quería implementar una animación 1: 1 del antiguo controlador de vista al mismo tiempo que la nueva vista aparece el controlador Esto tiene el efecto de hacer que los dos controladores de vista parezcan fijados entre sí.
Para la operación de inserción, eso requiere primero establecer el toViewControllerorigen de la vista en el eje x fuera de la pantalla, agregarlo como la subvista del containerView, animándolo en la pantalla al ponerlo origin.xa cero. Al mismo tiempo, animé la fromViewControllervista de distancia al configurarla origin.xfuera de la pantalla:
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)
})
La operación pop es básicamente la inversa. Agregue el toViewControllercomo una subvista del containerView, y anime fromViewControllera la derecha como anima toViewControllerdesde la izquierda:
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)
})
Aquí hay un resumen de todo el archivo swift:
https://gist.github.com/alanzeino/603293f9da5cd0b7f6b60dc20bc766be