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 UINavigationController
Animation zwischen zwei Ansichts-Controllern zu kombinieren, wenn Sie eine Unterklasse UINavigationController
einer Klasse erstellen und eine Instanz einer Klasse zurückgeben, die dem UIViewControllerAnimatedTransitioning
Protokoll entspricht.
Zum Beispiel ist hier meine UINavigationController
Unterklasse:
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 UINavigationControllerDelegate
auf 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 NavigationControllerAnimation
der Implementierung des UIViewControllerAnimatedTransitioning
Protokolls 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 UIViewControllerAnimatedTransitioning
Protokoll 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 to
Ansichts-Controller als Unteransicht des containerView
im Ü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 Bool
zu 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 toViewController
Ansichtsursprung der Ansicht auf der x-Achse außerhalb des Bildschirms festgelegt, als Unteransicht der hinzugefügt containerView
und auf dem Bildschirm animiert werden , indem dieser Wert origin.x
auf Null gesetzt wird. Gleichzeitig animiere ich die fromViewController
Ansicht origin.x
des 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 toViewController
als Unteransicht des hinzu containerView
und animieren fromViewController
Sie das rechts weg , während Sie das toViewController
von 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