Es war einmal ein bescheidener View Controller VCYellow . Und er hatte weder ein Bild noch einen Text oder eine winzige Geschäftslogik. Er lebte ein gewöhnliches View-Controller-Leben.
Sein Kollege VCMain präsentierte es manchmal der Welt:
class VCMain: UIViewController { ... @IBAction func onBtnTapMeTapped(_ sender: Any) { let vcYellow = self.storyboard!.instantiateViewController(withIdentifier: "VCYellow") as! VCYellow self.present(vcYellow, animated: true, completion: nil) }
Und VCYellow wiederum versteckte sich mit Hilfe eines einzigen "X" -Knopfes, auf den er übrigens sehr stolz war:
class VCYellow: UIViewController { ... @IBAction func onBtnCloseTapped(_ sender: Any) { self.dismiss(animated: true, completion: nil) }
Und es sah nicht so schlimm aus, aber langweilig und banal:

Aber unser Held hatte einen Traum zu lernen, sich in Schönheit zu zeigen und zu verstecken. Ja, damit Sie diese Schönheit später in den Ferien oder nur zu Ehren einer guten Laune ändern können.

Jahre vergingen ... und so wäre der Traum ein Traum geblieben, wenn VCYellow nicht etwas über Magie gelernt hätte :
UIViewControllerTransitioningDelegate
Und die Kraft dieser Magie liegt in der Tatsache, dass es möglich ist, den entsprechenden Animator zu verschieben, um den Ansichts-Controller anzuzeigen und auszublenden. Genau das, wovon unser Controller geträumt hat.
Er las in alten Schriftrollen, wie man den Zauber benutzt, und begann sich vorzubereiten.
Ich schrieb eine Krippe mit dem Zauber selbst auf, um nicht zu vergessen:
extension VCYellow: UIViewControllerTransitioningDelegate { func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { return AnimatorPresent(startFrame: self.startFrame) } func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return AnimatorDismiss(endFrame: self.startFrame) } }
Darin malte er sorgfältig, dass Sie für die Show den Animator AnimatorPresent verwenden müssen und wenn Sie AnimatorDismiss schließen.
Nun, als Hilfe für beide Animatoren wurde beschlossen, den Hauptschaltflächenrahmen von VCMain zu übertragen
Und dann war er selbst mental eingestellt. Denn ohne die richtige Einstellung funktioniert, wie Sie wissen, keine Magie:
override func viewDidLoad() { super.viewDidLoad() self.modalPresentationStyle = .custom self.transitioningDelegate = self }
Er bat seinen Freund VCMain, sich vorzustellen, um zu überprüfen, wie die Magie funktioniert und ... es funktionierte in keiner Weise ...
Es stellte sich heraus, dass AnimatorPresent und AnimatorDismiss nicht von selbst angezeigt werden.
Es war zu spät, um aufzuhören, und unser Held beschloss, die notwendigen Animatoren zu erstellen. Ich stöberte in dem notwendigen Abschnitt der alten Schriftrollen herum und fand heraus, dass zwei Dinge ausreichen, um einen Animator zu erstellen.
Zunächst müssen Sie die für die Animation vorgesehene Zeit festlegen:
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.3 }
und zweitens die Animation selbst angeben:
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { //1 guard let vcTo = transitionContext.viewController(forKey: .to), let snapshot = vcTo.view.snapshotView(afterScreenUpdates: true) else { return } //2 let vContainer = transitionContext.containerView //3 vcTo.view.isHidden = true vContainer.addSubview(vcTo.view) //4 snapshot.frame = self.startFrame vContainer.addSubview(snapshot) UIView.animate(withDuration: 0.3, animations: { //5 snapshot.frame = (transitionContext.finalFrame(for: vcTo)) }, completion: { success in //6 vcTo.view.isHidden = false snapshot.removeFromSuperview() transitionContext.completeTransition(true) }) }
- Ziehen Sie den vorgestellten View Controller (in unserem Fall VCYellow) heraus und machen Sie ein Foto davon. Ein Foto wird benötigt, um die Animation zu vereinfachen.
- Verschaffen Sie sich einen Überblick darüber, welche animierte Hexerei stattfinden wird. Nennen wir es Kontext.
- Verbinden Sie die Ansicht des endgültigen Controllers mit dem Kontext und blenden Sie ihn aus. Zeigen
- Es wurde entschieden, nachdem die Animation beendet war.
- Bereiten Sie ein Foto für die Animation vor. Auf die ursprüngliche Größe reduzieren und auf den Kontext werfen.
- Teilen Sie das Foto in den Vollbildmodus und animieren Sie so den Präsentationsprozess.
- Zeigen Sie nach Abschluss der Animation die reale Ansicht des endgültigen Controllers.
- Entfernen Sie das Foto und melden Sie, dass die Aktion beendet ist.
Infolgedessen gab es einen solchen Animator zur Anzeige:
import UIKit class AnimatorPresent: NSObject, UIViewControllerAnimatedTransitioning { let startFrame: CGRect init(startFrame: CGRect) { self.startFrame = startFrame } func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.3 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let vcTo = transitionContext.viewController(forKey: .to), let snapshot = vcTo.view.snapshotView(afterScreenUpdates: true) else { return } let vContainer = transitionContext.containerView vcTo.view.isHidden = true vContainer.addSubview(vcTo.view) snapshot.frame = self.startFrame vContainer.addSubview(snapshot) UIView.animate(withDuration: 0.3, animations: { snapshot.frame = (transitionContext.finalFrame(for: vcTo)) }, completion: { success in vcTo.view.isHidden = false snapshot.removeFromSuperview() transitionContext.completeTransition(true) }) } }
Und danach war es nicht schwierig, einen Animator zum Verstecken zu schreiben, der ungefähr dasselbe tut, aber umgekehrt:
import UIKit class AnimatorDismiss: NSObject, UIViewControllerAnimatedTransitioning { let endFrame: CGRect init(endFrame: CGRect) { self.endFrame = endFrame } func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.3 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let vcTo = transitionContext.viewController(forKey: .to), let vcFrom = transitionContext.viewController(forKey: .from), let snapshot = vcFrom.view.snapshotView(afterScreenUpdates: true) else { return } let vContainer = transitionContext.containerView vContainer.addSubview(vcTo.view) vContainer.addSubview(snapshot) vcFrom.view.isHidden = true UIView.animate(withDuration: 0.3, animations: { snapshot.frame = self.endFrame }, completion: { success in transitionContext.completeTransition(true) }) } }
Nachdem VCYellow den letzten Schliff erledigt hatte , bat er seinen Freund VCMain erneut, sich vorzustellen und siehe da !

Die Magie hat funktioniert! VCYellow's Traum wurde wahr! Jetzt kann er zeigen und sich verstecken, wie er will und nichts wird seine Fantasie einschränken!
Ein Beispielprojekt kann hier heruntergeladen werden.
Der Artikel, den ich als Inspiration verwendet habe, ist hier.