Étant donné que c'est le meilleur résultat sur Google, j'ai pensé partager ce que je pense être la manière la plus sensée; qui consiste à utiliser l'API de transition iOS 7+. J'ai implémenté cela pour iOS 10 avec Swift 3.
Il est assez simple de combiner cela avec la façon dont UINavigationControllers'anime entre deux contrôleurs de vue si vous créez une sous-classe de UINavigationControlleret renvoyez une instance d'une classe conforme au UIViewControllerAnimatedTransitioningprotocole.
Par exemple, voici ma UINavigationControllersous - classe:
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)
}
}
Vous pouvez voir que je mets le UINavigationControllerDelegateà lui-même, et dans une extension de ma sous-classe, j'implémente la méthode UINavigationControllerDelegatequi vous permet de retourner un contrôleur d'animation personnalisé (c'est-à-dire NavigationControllerAnimation). Ce contrôleur d'animation personnalisé remplacera l'animation stock pour vous.
Vous vous demandez probablement pourquoi je passe l'opération à l' NavigationControllerAnimationinstance via son initialiseur. Je le fais pour que dans NavigationControllerAnimationla mise en œuvre du UIViewControllerAnimatedTransitioningprotocole, je sache quelle est l'opération (c'est-à-dire «pousser» ou «pop»). Cela permet de savoir quel type d'animation je dois faire. La plupart du temps, vous souhaitez effectuer une animation différente en fonction de l'opération.
Le reste est assez standard. Implémentez les deux fonctions requises dans le UIViewControllerAnimatedTransitioningprotocole et animez comme vous le souhaitez:
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
}
}
}
Il est important de se rappeler que pour chaque type d'opération différent (c'est-à-dire «pousser» ou «pop»), les contrôleurs de vue vers et depuis seront différents. Lorsque vous êtes en mode push, le contrôleur to view sera celui qui est poussé. Lorsque vous êtes dans une opération de pop, le contrôleur de vue sera celui vers lequel la transition est effectuée et le contrôleur de vue sera celui qui sera sauté.
En outre, le tocontrôleur de vue doit être ajouté en tant que sous-vue de containerViewdans le contexte de transition.
Une fois votre animation terminée, vous devez appeler transitionContext.completeTransition(true). Si vous effectuez une transition interactive, vous devrez retourner dynamiquement un Boolà completeTransition(didComplete: Bool), selon que la transition est terminée à la fin de l'animation.
Enfin ( lecture facultative ), vous voudrez peut-être voir comment j'ai effectué la transition sur laquelle je travaillais. Ce code est un peu plus hacky et je l'ai écrit assez rapidement donc je ne dirais pas que c'est un excellent code d'animation mais il montre toujours comment faire la partie animation.
La mienne était une transition vraiment simple; Je voulais imiter la même animation que UINavigationController, mais au lieu de l'animation `` page suivante en haut '', je voulais implémenter une animation 1: 1 de l'ancien contrôleur de vue en même temps que la nouvelle vue contrôleur apparaît. Cela a pour effet de donner l'impression que les deux contrôleurs de vue sont attachés l'un à l'autre.
Pour l'opération de poussée, cela nécessite d'abord de définir l' toViewControllerorigine de la vue du sur l'écran hors axe x, de l'ajouter comme sous-vue du containerView, de l'animer sur l'écran en la mettant origin.xà zéro. En même temps, j'anime la fromViewControllervue en la origin.xdésactivant de l'écran:
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)
})
L'opération pop est essentiellement l'inverse. Ajoutez le en toViewControllertant que sous-vue du containerView, et animez le fromViewControllervers la droite pendant que vous l'animez toViewControllerdepuis la gauche:
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)
})
Voici un aperçu de l'ensemble du fichier Swift:
https://gist.github.com/alanzeino/603293f9da5cd0b7f6b60dc20bc766be