Como esse é o melhor resultado no Google, pensei em compartilhar o que considero a maneira mais sensata; que é usar a API de transição do iOS 7+. Eu implementei isso no iOS 10 com o Swift 3.
É bem simples combinar isso com como UINavigationController anima entre dois controladores de exibição, se você criar uma subclasse UINavigationControllere retornar uma instância de uma classe que esteja em conformidade com o UIViewControllerAnimatedTransitioningprotocolo.
Por exemplo, aqui está o meu UINavigationController subclasse:
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)
}
}
Você pode ver que eu defino o valor UINavigationControllerDelegateem si e, em uma extensão da minha subclasse, implemento o método em UINavigationControllerDelegateque permite retornar um controlador de animação personalizado (por exemplo, NavigationControllerAnimation). Este controlador de animação personalizado substituirá a animação de estoque para você.
Você provavelmente está se perguntando por que eu passo a operação para o NavigationControllerAnimation instância por meio de seu inicializador. Eu faço isso para que na NavigationControllerAnimationimplementação do UIViewControllerAnimatedTransitioningprotocolo eu saiba qual é a operação (ou seja, 'push' ou 'pop'). Isso ajuda a saber que tipo de animação devo fazer. Na maioria das vezes, você deseja executar uma animação diferente, dependendo da operação.
O resto é bastante padrão. Implemente as duas funções necessárias noUIViewControllerAnimatedTransitioning protocolo e anime da maneira que desejar:
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
}
}
}
É importante lembrar que, para cada tipo diferente de operação (por exemplo, 'push' ou 'pop'), os controladores de e para a visualização serão diferentes. Quando você estiver em uma operação de envio, o controlador para visualizar será o que está sendo enviado. Quando você está em uma operação pop, o controlador de visualização será aquele que está sendo transferido e o controlador de visualização será o que está sendo exibido.
Além disso, o tocontrolador de exibição deve ser adicionado como uma subvisão docontainerView no contexto de transição.
Quando sua animação terminar, você deve ligar transitionContext.completeTransition(true). Se você estiver fazendo uma transição interativa, será necessário retornar dinamicamente BoolacompleteTransition(didComplete: Bool) , dependendo se a transição estiver concluída no final da animação.
Finalmente ( leitura opcional ), você pode querer ver como eu fiz a transição em que estava trabalhando. Esse código é um pouco mais hacky e eu o escrevi rapidamente, então não diria que é um ótimo código de animação, mas ainda mostra como fazer a parte da animação.
A minha foi uma transição realmente simples; Eu queria imitar a mesma animação que o UINavigationController normalmente faz, mas, em vez da animação 'próxima página por cima', eu queria implementar uma animação 1: 1 do antigo controlador de exibição ao mesmo tempo que a nova exibição controlador aparece. Isso tem o efeito de fazer com que os dois controladores de exibição pareçam estar presos um ao outro.
Para a operação push, é necessário primeiro definir a toViewControllerorigem da vista da tela no eixo x fora da tela, adicionando-a como subvisão do containerView, animando-a na tela, definindo- origin.xa como zero. Ao mesmo tempo, animar a fromViewControllervista de fora definindo origin.x-a na tela:
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)
})
A operação pop é basicamente o inverso. Adicione a toViewControllercomo uma subvisão de containerViewe animar fromViewControllerpara a direita como você anima na toViewControllerda esquerda:
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)
})
Aqui está uma essência com todo o arquivo rápido:
https://gist.github.com/alanzeino/603293f9da5cd0b7f6b60dc20bc766be