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 UINavigationController
anima entre dos controladores de vista si crea una subclase de UINavigationController
y devuelve una instancia de una clase que se ajusta al UIViewControllerAnimatedTransitioning
protocolo.
Por ejemplo, aquí está mi UINavigationController
subclase:
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 UINavigationControllerDelegate
mismo y, en una extensión de mi subclase, implemento el método UINavigationControllerDelegate
que 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 NavigationControllerAnimation
instancia a través de su inicializador. Hago esto para que en NavigationControllerAnimation
la 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 UIViewControllerAnimatedTransitioning
protocolo 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 to
controlador de vista debe agregarse como una subvista del containerView
contexto 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 Bool
a 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 toViewController
origen 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.x
a cero. Al mismo tiempo, animé la fromViewController
vista de distancia al configurarla origin.x
fuera 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 toViewController
como una subvista del containerView
, y anime fromViewController
a la derecha como anima toViewController
desde 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