wake-up-neo.com

RootViewController-Switch-Übergangsanimation

Gibt es eine Möglichkeit, einen Übergangs-/Animationseffekt zu erzielen, während ein vorhandener Viewcontroller als Rootviewcontroller durch einen neuen in der appDelegate ersetzt wird?

120
Jefferson

Sie können das Umschalten der rootViewController in einen Übergangsanimationsblock einschließen:

[UIView transitionWithView:self.window
                  duration:0.5
                   options:UIViewAnimationOptionTransitionFlipFromLeft
                animations:^{ self.window.rootViewController = newViewController; }
                completion:nil];
269
Ole Begemann

Ich habe das gefunden und funktioniert perfekt:

in deiner appDelegate:

- (void)changeRootViewController:(UIViewController*)viewController {

    if (!self.window.rootViewController) {
        self.window.rootViewController = viewController;
        return;
    }

    UIView *snapShot = [self.window snapshotViewAfterScreenUpdates:YES];

    [viewController.view addSubview:snapShot];

    self.window.rootViewController = viewController;

    [UIView animateWithDuration:0.5 animations:^{
        snapShot.layer.opacity = 0;
        snapShot.layer.transform = CATransform3DMakeScale(1.5, 1.5, 1.5);
    } completion:^(BOOL finished) {
        [snapShot removeFromSuperview];
    }];
}

in deiner App

 if (!app) { app = (AppDelegate *)[[UIApplication sharedApplication] delegate]; }
        [app changeRootViewController:newViewController];

credits:

https://Gist.github.com/gimenete/53704124583b5df3b407

65
Jesus

Ich poste die Antwort von Jesus in Swift. Es verwendet den Bezeichner von Viewcontroller als Argument, lädt von Storyboard (wantViewController) und ändert rootViewController mit Animation.

Swift 3.0 Update:

  func changeRootViewController(with identifier:String!) {
    let storyboard = self.window?.rootViewController?.storyboard
    let desiredViewController = storyboard?.instantiateViewController(withIdentifier: identifier);

    let snapshot:UIView = (self.window?.snapshotView(afterScreenUpdates: true))!
    desiredViewController?.view.addSubview(snapshot);

    self.window?.rootViewController = desiredViewController;

    UIView.animate(withDuration: 0.3, animations: {() in
      snapshot.layer.opacity = 0;
      snapshot.layer.transform = CATransform3DMakeScale(1.5, 1.5, 1.5);
      }, completion: {
        (value: Bool) in
        snapshot.removeFromSuperview();
    });
  }

Swift 2.2 Update:

  func changeRootViewControllerWithIdentifier(identifier:String!) {
    let storyboard = self.window?.rootViewController?.storyboard
    let desiredViewController = storyboard?.instantiateViewControllerWithIdentifier(identifier);

    let snapshot:UIView = (self.window?.snapshotViewAfterScreenUpdates(true))!
    desiredViewController?.view.addSubview(snapshot);

    self.window?.rootViewController = desiredViewController;

    UIView.animateWithDuration(0.3, animations: {() in
      snapshot.layer.opacity = 0;
      snapshot.layer.transform = CATransform3DMakeScale(1.5, 1.5, 1.5);
      }, completion: {
        (value: Bool) in
        snapshot.removeFromSuperview();
    });
  }

  class func sharedAppDelegate() -> AppDelegate? {
    return UIApplication.sharedApplication().delegate as? AppDelegate;
  }

Danach haben Sie eine sehr einfache Verwendung von überall:

let appDelegate = AppDelegate.sharedAppDelegate()
appDelegate?.changeRootViewControllerWithIdentifier("YourViewControllerID")

Swift 3.0 Update

let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.changeRootViewController(with: "listenViewController")
38

// In Swift:

UIView.transitionWithView(self.window!, duration: 0.5, options: UIViewAnimationOptions.TransitionFlipFromLeft, animations: {
  self.window?.rootViewController = anyViewController
}, completion: nil)
20

probiere es einfach aus. Funktioniert gut für mich.

BOOL oldState = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled:NO];
self.window.rootViewController = viewController;
[UIView transitionWithView:self.window duration:0.5 options:transition animations:^{
    //
} completion:^(BOOL finished) {
    [UIView setAnimationsEnabled:oldState];
}];

BEARBEITEN:

Dieses hier ist besser.

- (void)setRootViewController:(UIViewController *)viewController
               withTransition:(UIViewAnimationOptions)transition
                   completion:(void (^)(BOOL finished))completion {
    UIViewController *oldViewController = self.window.rootViewController;
    [UIView transitionFromView:oldViewController.view 
                        toView:viewController.view
                      duration:0.5f
                       options:(UIViewAnimationOptions)(transition|UIViewAnimationOptionAllowAnimatedContent|UIViewAnimationOptionLayoutSubviews)
                    completion:^(BOOL finished) {
        self.window.rootViewController = viewController;
        if (completion) {
            completion(finished);
        }
    }];
}
10
Dmitry Coolerov

Um später in der App keine Probleme mit dem Übergangs-Flip zu haben, ist es gut, die alte Ansicht auch vom Stapel zu löschen

UIViewController *oldController=self.window.rootViewController;

[UIView transitionWithView:self.window
                  duration:0.5
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{ self.window.rootViewController = nav; }
                completion:^(BOOL finished) {
                    if(oldController!=nil)
                        [oldController.view removeFromSuperview];
                }];
3
Catalin

Dies ist ein Update für Swift 3. Diese Methode sollte in Ihrem App-Delegaten enthalten sein, und Sie rufen es von einem beliebigen Ansichtscontroller aus über eine gemeinsam genutzte Instanz des App-Delegaten auf

func logOutAnimation() {
    let storyBoard = UIStoryboard.init(name: "SignIn", bundle: nil)
    let viewController = storyBoard.instantiateViewController(withIdentifier: "signInVC")
    UIView.transition(with: self.window!, duration: 0.5, options: UIViewAnimationOptions.transitionFlipFromLeft, animations: {
        self.window?.rootViewController = viewController
        self.window?.makeKeyAndVisible()
    }, completion: nil)
}

Der Teil, der in verschiedenen Fragen oben fehlt, ist 

    self.window?.makeKeyAndVisible()

Hoffe das hilft jemandem.

2

Die richtige Antwort ist, dass Sie die rootViewController in Ihrem Fenster nicht ersetzen müssen. Erstellen Sie stattdessen eine benutzerdefinierte UIViewController, weisen Sie sie einmal zu und lassen Sie sie jeweils einen untergeordneten Controller anzeigen und bei Bedarf durch eine Animation ersetzen. Sie können den folgenden Code als Ausgangspunkt verwenden:

Swift 3.0

import Foundation
import UIKit

/// Displays a single child controller at a time.
/// Replaces the current child controller optionally with animation.
class FrameViewController: UIViewController {

    private(set) var displayedViewController: UIViewController?

    func display(_ viewController: UIViewController, animated: Bool = false) {

        addChildViewController(viewController)

        let oldViewController = displayedViewController

        view.addSubview(viewController.view)
        viewController.view.layoutIfNeeded()

        let finishDisplay: (Bool) -> Void = {
            [weak self] finished in
            if !finished { return }
            oldViewController?.view.removeFromSuperview()
            oldViewController?.removeFromParentViewController()
            viewController.didMove(toParentViewController: self)
        }

        if (animated) {
            viewController.view.alpha = 0
            UIView.animate(
                withDuration: 0.5,
                animations: { viewController.view.alpha = 1; oldViewController?.view.alpha = 0 },
                completion: finishDisplay
            )
        }
        else {
            finishDisplay(true)
        }

        displayedViewController = viewController
    }

    override var preferredStatusBarStyle: UIStatusBarStyle {
        return displayedViewController?.preferredStatusBarStyle ?? .default
    }
}

Und wie Sie es verwenden, ist:

...
let rootController = FrameViewController()
rootController.display(UINavigationController(rootViewController: MyController()))
window.rootViewController = rootController
window.makeKeyAndVisible()
...

Das obige Beispiel zeigt, dass Sie UINavigationController in FrameViewController verschachteln können, und das funktioniert einwandfrei. Dieser Ansatz bietet Ihnen ein hohes Maß an Anpassung und Kontrolle. Rufen Sie einfach FrameViewController.display(_) auf, wenn Sie den Root-Controller in Ihrem Fenster ersetzen möchten, und der Job wird für Sie erledigt.

2
Aleks N.

in AppDelegate.h:

#define ApplicationDelegate ((AppDelegate *)[UIApplication sharedApplication].delegate)]

in Ihrem Controller:

[UIView transitionWithView:self.window
                  duration:0.5
                   options:UIViewAnimationOptionTransitionFlipFromLeft
                animations:^{
    ApplicationDelegate.window.rootViewController = newViewController;
    }
                completion:nil];
1
Khwarezm Shah

Schöne süße Animation (getestet mit Swift 4.x):

extension AppDelegate {
   public func present(viewController: UIViewController) {
        guard let window = window else { return }
        UIView.transition(with: window, duration: 0.5, options: .transitionFlipFromLeft, animations: {
            window.rootViewController = viewController
        }, completion: nil)
    }
}

Rufen Sie mit an

guard let delegate = UIApplication.shared.delegate as? AppDelegate else { return }
delegate.present(viewController: UIViewController())
0
Cesare

Ich schlage meinen Weg vor, der in meinem Projekt gut funktioniert, und er bietet mir gute Animationen. Ich habe andere Vorschläge in diesem Beitrag getestet, aber einige von ihnen funktionieren nicht wie erwartet.

- (void)transitionToViewController:(UIViewController *)viewController withTransition:(UIViewAnimationOptions)transition completion:(void (^)(BOOL finished))completion {
// Reset new RootViewController to be sure that it have not presented any controllers
[viewController dismissViewControllerAnimated:NO completion:nil];

[UIView transitionWithView:self.window
                  duration:0.5f
                   options:transition
                animations:^{
                    for (UIView *view in self.window.subviews) {
                        [view removeFromSuperview];
                    }
                    [self.window addSubview:viewController.view];

                    self.window.rootViewController = viewController;
                } completion:completion];
}
0