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 UINavigationController
e retornar uma instância de uma classe que esteja em conformidade com o UIViewControllerAnimatedTransitioning
protocolo.
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 UINavigationControllerDelegate
em si e, em uma extensão da minha subclasse, implemento o método em UINavigationControllerDelegate
que 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 NavigationControllerAnimation
implementação do UIViewControllerAnimatedTransitioning
protocolo 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 to
controlador 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 Bool
acompleteTransition(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 toViewController
origem da vista da tela no eixo x fora da tela, adicionando-a como subvisão do containerView
, animando-a na tela, definindo- origin.x
a como zero. Ao mesmo tempo, animar a fromViewController
vista 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 toViewController
como uma subvisão de containerView
e animar fromViewController
para a direita como você anima na toViewController
da 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