将rootViewController与动画交换?


75

我试图用标签栏交换到另一个根视图控制器;通过应用程序委托,我想添加过渡动画。默认情况下,它将仅显示视图而没有任何动画。

let tabBar = self.instantiateViewController(storyBoard: "Main", viewControllerID: "MainTabbar")
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window = UIWindow(frame: UIScreen.main.bounds)
appDelegate.window?.rootViewController = tabBar
appDelegate.window?.makeKeyAndVisible()

这就是我换成另一个rootview控制器的方式。

Answers:


188

您可以使用UIView.transition(with: view)替换rootViewControllerUIWindow

guard let window = UIApplication.shared.keyWindow else {
    return
}

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "MainTabbar")

// Set the new rootViewController of the window.
// Calling "UIView.transition" below will animate the swap.
window.rootViewController = vc

// A mask of options indicating how you want to perform the animations.
let options: UIView.AnimationOptions = .transitionCrossDissolve

// The duration of the transition animation, measured in seconds.
let duration: TimeInterval = 0.3

// Creates a transition animation.
// Though `animations` is optional, the documentation tells us that it must not be nil. ¯\_(ツ)_/¯
UIView.transition(with: window, duration: duration, options: options, animations: {}, completion:
{ completed in
    // maybe do something on completion here
})

做得很好(Y)。
Itzdsp


我对此有轻微的动画故障。在rootViewController.view.frame不包括状态栏架我。必须手动调整框架以考虑占用顶部20个像素的状态栏。
马克·布里奇斯

只是指出:选项参数在这里什么也不做。
MarekStaňa,

@MarekStaňa你在说什么.transitionCrossDissolveduration如果您看不到淡入淡出效果,则可能需要增加。0.3秒很容易错过。我刚刚测试了它-仍然可以使用:)
d.felber

22

斯威夫特4

将功能粘贴到AppDelegate

func setRootViewController(_ vc: UIViewController, animated: Bool = true) {
    guard animated, let window = self.window else {
        self.window?.rootViewController = vc
        self.window?.makeKeyAndVisible()
        return
    }

    window.rootViewController = vc
    window.makeKeyAndVisible()
    UIView.transition(with: window,
                      duration: 0.3,
                      options: .transitionCrossDissolve,
                      animations: nil,
                      completion: nil)
}

如果我同时使用appdelegate和scenedelegate怎么办?
Jaseel.Dev

17

替代解决方案:

let stb = UIStoryboard(name: "YOUR_STORYBOARD_NAME", bundle: nil)
let rootVC = stb.instantiateViewController(withIdentifier: "YOUR_TABBAR_VIEWCONTROLLER_NAME")
let snapshot = (UIApplication.shared.keyWindow?.snapshotView(afterScreenUpdates: true))!
rootVC.view.addSubview(snapshot)

UIApplication.shared.keyWindow?.rootViewController = rootVC
UIView.transition(with: snapshot, 
                  duration: 0.4,
                  options: .transitionCrossDissolve,
                  animations: { 
                      snapshot.layer.opacity = 0
                  },
                  completion: { status in 
                      snapshot.removeFromSuperview()
                  })

12

我试图交换到另一个根视图控制器...,我想添加过渡动画

我有一个执行此操作的应用程序:它使用动画更改了根视图控制器(称为白蛋白)。

但是我的应用程序实际上并没有真正更改根视图控制器。根视图控制器是一个永不更改的自定义容器视图控制器。它的视图从未见过,并且没有任何功能。它唯一的工作就是发生更改的地方:它将一个子视图控制器替换为另一个子视图控制器-这样过渡动画就可以工作。

换句话说,您将一个视图控制器添加到您的视图控制器层次结构中,就在该层次结构的顶部,这样,整个问题就可以很好地正确解决。


很棒的主意,我在SwiftUI中进行了这项工作,这使我的生活变得更好了!
Mike Taverne'5

9

尝试这个:

UIView.transition(from: appdelegate.window.rootViewController!.view, to: tabbar.view, duration: 0.6, options: [.transitionCrossDissolve], completion: {
    _ in
    appdelegate.window.rootViewController = tabbar
})

1
这实际上工作得很好。尽管我希望提供的动画类型更多。
Vahid Amiri '18

轻松自在!
Reimond Hill '18

-1

我基于d.felber的答案为此创建了一个帮助器类:


    import UIKit

    class ViewPresenter {

        public static func replaceRootView(for viewController: UIViewController,
                                   duration: TimeInterval = 0.3,
                                   options: UIView.AnimationOptions = .transitionCrossDissolve,
                                   completion: ((Bool) -> Void)? = nil) {
            guard let window = UIApplication.shared.keyWindow else {
                return
            }

            guard let rootViewController = window.rootViewController else {
                return
            }

            viewController.view.frame = rootViewController.view.frame
            viewController.view.layoutIfNeeded()

            UIView.transition(with: window, duration: duration, options: options, animations: {
                window.rootViewController = viewController
            }, completion: completion)
        }
    }

您可以像这样使用它:

    let loginVC = SignInViewController(nibName: "SignInViewController", bundle: nil)
    ViewPresenter.replaceRootView(for: loginVC)

要么

ViewPresenter.replaceRootView(for: loginVC, duration: 0.3, options: .transitionCrossDissolve) { 
(bool) in
       // do something
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.