Da dies das Top-Ergebnis bei Google ist, dachte ich, ich würde mitteilen, was meiner Meinung nach der vernünftigste Weg ist. Dies ist die Verwendung der iOS 7+ -Übergangs-API. Ich habe dies für iOS 10 mit Swift 3 implementiert.
Es ist ziemlich einfach, dies mit der UINavigationControllerAnimation zwischen zwei Ansichts-Controllern zu kombinieren, wenn Sie eine Unterklasse UINavigationControllereiner Klasse erstellen und eine Instanz einer Klasse zurückgeben, die dem UIViewControllerAnimatedTransitioningProtokoll entspricht.
Zum Beispiel ist hier meine UINavigationControllerUnterklasse:
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)
}
}
Sie können sehen, dass ich das UINavigationControllerDelegateauf sich selbst setze , und in einer Erweiterung in meiner Unterklasse implementiere ich die Methode UINavigationControllerDelegate, mit der Sie einen benutzerdefinierten Animationscontroller (dh NavigationControllerAnimation) zurückgeben können. Dieser benutzerdefinierte Animationscontroller ersetzt die Standardanimation für Sie.
Sie fragen sich wahrscheinlich, warum ich die Operation NavigationControllerAnimationüber ihren Initialisierer an die Instanz übergebe. Ich mache das so, dass ich bei NavigationControllerAnimationder Implementierung des UIViewControllerAnimatedTransitioningProtokolls weiß, was die Operation ist (dh 'Push' oder 'Pop'). Dies hilft zu wissen, welche Art von Animation ich machen soll. Meistens möchten Sie je nach Vorgang eine andere Animation ausführen.
Der Rest ist ziemlich normal. Implementieren Sie die beiden erforderlichen Funktionen im UIViewControllerAnimatedTransitioningProtokoll und animieren Sie, wie Sie möchten:
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 ist wichtig zu bedenken, dass für jede Art von Operation (dh 'Push' oder 'Pop') die Zu- und Ab-Controller unterschiedlich sind. Wenn Sie sich in einer Push-Operation befinden, wird der Controller für die Anzeige angezeigt. Wenn Sie sich in einem Pop-Vorgang befinden, wird der Controller für die Ansicht angezeigt, auf den umgestellt wird, und der Controller für die Ansicht wird angezeigt.
Außerdem muss der toAnsichts-Controller als Unteransicht des containerViewim Übergangskontext hinzugefügt werden .
Wenn Ihre Animation abgeschlossen ist, müssen Sie anrufen transitionContext.completeTransition(true). Wenn Sie einen interaktiven Übergang tun, müssen Sie dynamisch eine Rückkehr Boolzu completeTransition(didComplete: Bool), je nachdem , ob der Übergang am Ende der Animation abgeschlossen ist.
Schließlich ( optionales Lesen ) möchten Sie vielleicht sehen, wie ich den Übergang gemacht habe, an dem ich gearbeitet habe. Dieser Code ist etwas hackiger und ich habe ihn ziemlich schnell geschrieben, daher würde ich nicht sagen, dass er großartiger Animationscode ist, aber er zeigt immer noch, wie man den Animationsteil macht.
Meins war ein wirklich einfacher Übergang; Ich wollte dieselbe Animation nachahmen, die UINavigationController normalerweise ausführt, aber anstelle der Animation "Nächste Seite über dem oberen Rand" wollte ich gleichzeitig mit der neuen Ansicht eine 1: 1-Animation des alten Ansichts-Controllers implementieren Controller erscheint. Dies hat den Effekt, dass die beiden Ansichts-Controller so aussehen, als wären sie miteinander verbunden.
Für den Push-Vorgang muss zuerst der toViewControllerAnsichtsursprung der Ansicht auf der x-Achse außerhalb des Bildschirms festgelegt, als Unteransicht der hinzugefügt containerViewund auf dem Bildschirm animiert werden , indem dieser Wert origin.xauf Null gesetzt wird. Gleichzeitig animiere ich die fromViewControllerAnsicht origin.xdes Bildschirms, indem ich sie vom Bildschirm aus deaktiviere:
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)
})
Die Pop-Operation ist im Grunde die Umkehrung. Fügen Sie das toViewControllerals Unteransicht des hinzu containerViewund animieren fromViewControllerSie das rechts weg , während Sie das toViewControllervon links animieren :
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)
})
Hier ist ein Kern der gesamten schnellen Datei:
https://gist.github.com/alanzeino/603293f9da5cd0b7f6b60dc20bc766be