ios RootViewController 切换过渡动画

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7703806/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 21:47:49  来源:igfitidea点击:

RootViewController Switch Transition Animation

objective-ciosxcodecocoa-touch

提问by Jefferson

Is there any way to have a Transition/animation effect while replacing an existing viewcontroller as rootviewcontroller with a new one in the appDelegate?

有什么方法可以在将现有的视图控制器替换为根视图控制器的同时使用 appDelegate 中的新视图控制器来实现过渡/动画效果?

回答by Ole Begemann

You can wrap the switching of the rootViewControllerin a transition animation block:

您可以将 的切换包装rootViewController在过渡动画块中:

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

回答by Jesus

I found this and works perfectly:

我发现了这个并且完美地工作:

in your appDelegate:

在您的 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 your app

在您的应用程序中

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

credits:

学分:

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

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

回答by Neil Galiaskarov

I am posting Jesus answer implemented in swift. It takes viewcontroller's identifier as an argument, loads from storyboard desiredViewController and changes rootViewController with animation.

我正在发布快速实施的耶稣答案。它以viewcontroller 的标识符作为参数,从storyboard 中加载desiredViewController 并用动画改变rootViewController。

Swift 3.0 Update:

斯威夫特 3.0 更新:

  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:

斯威夫特 2.2 更新:

  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;
  }

After, you have a very simple usage from anywhere:

之后,您可以在任何地方进行非常简单的使用:

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

Swift 3.0 update

斯威夫特 3.0 更新

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

回答by Chandrashekhar H M

Swift 2

斯威夫特 2

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

Swift 3, 4, 5

斯威夫特 3、4、5

UIView.transition(with: self.window!, duration: 0.5, options: UIView.AnimationOptions.transitionFlipFromLeft, animations: {
  self.window?.rootViewController = anyViewController
}, completion: nil)

回答by Dmitry Coolerov

just try this. Works fine for me.

试试这个。对我来说很好用。

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];
}];

EDIT:

编辑:

This one is better.

这个更好。

- (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);
        }
    }];
}

回答by Catalin

In order not to have problems with transition flip later on in the app is good to clear the old view from the stack as well

为了稍后在应用程序中不出现过渡翻转问题,最好也从堆栈中清除旧视图

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];
                }];

回答by Aleks N.

The correct answer is you don't need to replace the rootViewControlleron your window. Instead, create a custom UIViewController, assign it once and let it display one child controller at a time and replace it with animation if needed. You can use the following piece of code as a starting point:

正确答案是您不需要更换rootViewController窗户上的 。相反,创建一个 custom UIViewController,分配一次并让它一次显示一个子控制器,并在需要时将其替换为动画。您可以使用以下代码作为起点:

Swift 3.0

斯威夫特 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
    }
}

And the way you use it is:

你使用它的方式是:

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

The example above demonstrates that you can nest UINavigationControllerinside FrameViewControllerand that works just fine. This approach gives you high level of customization and control. Just call FrameViewController.display(_)any time you would want to replace the root controller on your window, and it will do that job for you.

上面的例子表明你可以嵌套UINavigationController在里面FrameViewController并且工作得很好。这种方法为您提供了高级别的定制和控制。只需在FrameViewController.display(_)您想要替换窗口上的根控制器时随时调用,它就会为您完成这项工作。

回答by Giovanny Pi?eros

This is an update for swift 3, this method should be in your app delegate, and you call it from any view controller, via a shared instance of the app delegate

这是 swift 3 的更新,此方法应该在您的应用程序委托中,您可以通过应用程序委托的共享实例从任何视图控制器调用它

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)
}

The part that is missing from various questions above, is

上面各种问题中缺少的部分是

    self.window?.makeKeyAndVisible()

Hope this helps someone.

希望这可以帮助某人。

回答by Bob

in AppDelegate.h:

在 AppDelegate.h 中:

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

in your Controller:

在您的控制器中:

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

回答by 93sauu

I propose my way which it is working fine in my project, and it offers me good animations. I have tested other proposals found in this post, but some of them do not work as expected.

我提出了我的方法,它在我的项目中运行良好,并为我提供了很好的动画。我已经测试了这篇文章中发现的其他建议,但其中一些没有按预期工作。

- (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];
}