-
-
Save nvkiet/6368d1d45c4ea3e6d9cb to your computer and use it in GitHub Desktop.
func switchRootViewController(rootViewController: UIViewController, animated: Bool, completion: (() -> Void)?) { | |
if animated { | |
UIView.transitionWithView(window, duration: 0.5, options: .TransitionCrossDissolve, animations: { | |
let oldState: Bool = UIView.areAnimationsEnabled() | |
UIView.setAnimationsEnabled(false) | |
self.window!.rootViewController = rootViewController | |
UIView.setAnimationsEnabled(oldState) | |
}, completion: { (finished: Bool) -> () in | |
if completion { | |
completion!() | |
} | |
}) | |
} else { | |
window!.rootViewController = rootViewController | |
} | |
} |
Works a treat
Very useful method, thank you
Thanks, very useful :)
Here is a Swift 4 version
extension UIWindow {
func switchRootViewController(_ viewController: UIViewController, animated: Bool = true, duration: TimeInterval = 0.5, options: UIViewAnimationOptions = .transitionFlipFromRight, completion: (() -> Void)? = nil) {
guard animated else {
rootViewController = viewController
return
}
UIView.transition(with: self, duration: duration, options: options, animations: {
let oldState = UIView.areAnimationsEnabled
UIView.setAnimationsEnabled(false)
self.rootViewController = viewController
UIView.setAnimationsEnabled(oldState)
}) { _ in
completion?()
}
}
}
One more variation, use this as global function.
func switchRootViewController(rootViewController: UIViewController, animated: Bool, completion: (() -> Void)?) {
guard let window = UIApplication.shared.keyWindow else { return }
if animated {
UIView.transition(with: window, duration: 0.5, options: .transitionCrossDissolve, animations: {
let oldState: Bool = UIView.areAnimationsEnabled
UIView.setAnimationsEnabled(false)
window.rootViewController = rootViewController
UIView.setAnimationsEnabled(oldState)
}, completion: { (finished: Bool) -> () in
if (completion != nil) {
completion!()
}
})
} else {
window.rootViewController = rootViewController
}
}
Nice work! Thanks!!! 🍎
Make completion parameter optional.
func switchRootViewController(rootViewController: UIViewController, animated: Bool, completion: (() -> Swift.Void)? = nil) {
...
)
Warning: 'keyWindow' was deprecated in iOS 13.0: Should not be used for applications that support multiple scenes as it returns a key window across all connected scenes
What is the replacement for this? Any solution?
try this!
let scene = UIApplication.shared.connectedScenes.first
guard let windowScene = (scene as? UIWindowScene) else { return }
let window = UIWindow(windowScene: windowScene)
My solution is very simple. Inside your SceneDelegate.swift file add your function to update root view controller.
For example this is my function to change root widow to tab bar controller.
// SceneDelegate.swift
func moveToTabBarController() {
window?.rootViewController = createTabBar()
window?.makeKeyAndVisible()
}
And inside your view controller you can get access to scene delegate and call your change controller function.
let sceneDelegate = self.view.window?.windowScene?.delegate as! SceneDelegate
sceneDelegate.moveToTabBarController()
If you have sceneDelegate in your project use this:
let sb = UIStoryboard(name: "Main", bundle: nil)
let VC = sb.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
let navRootView = UINavigationController(rootViewController: VC)
self.present(navRootView, animated: true, completion: nil)
Swift 5.1
extension UIWindow {
func switchRootViewController(_ viewController: UIViewController,
animated: Bool = true,
duration: TimeInterval = 0.5,
options: AnimationOptions = .transitionFlipFromRight,
completion: (() -> Void)? = nil) {
guard animated else {
rootViewController = viewController
return
}
UIView.transition(with: self, duration: duration, options: options, animations: {
let oldState = UIView.areAnimationsEnabled
UIView.setAnimationsEnabled(false)
self.rootViewController = viewController
UIView.setAnimationsEnabled(oldState)
}, completion: { _ in
completion?()
})
}
}
Swift 5.1
extension UIWindow { func switchRootViewController(_ viewController: UIViewController, animated: Bool = true, duration: TimeInterval = 0.5, options: AnimationOptions = .transitionFlipFromRight, completion: (() -> Void)? = nil) { guard animated else { rootViewController = viewController return } UIView.transition(with: self, duration: duration, options: options, animations: { let oldState = UIView.areAnimationsEnabled UIView.setAnimationsEnabled(false) self.rootViewController = viewController UIView.setAnimationsEnabled(oldState) }, completion: { _ in completion?() }) } }
how I can implement this ?
@jesus003
let loginVC = QGLoginViewController.loadFromNib()
guard let window = self.view.window else {
return
}
window.switchRootViewController(to: loginVC)
Swift 5.5 with the introduction of async/await APIs
extension UIWindow {
@MainActor
func setRootViewController(_ newRootViewController: UIViewController, animated: Bool = true) async {
guard animated else {
rootViewController = newRootViewController
return
}
await withCheckedContinuation({ (continuation: CheckedContinuation<Void, Never>) in
UIView.transition(with: self, duration: 0.3, options: .transitionCrossDissolve) {
let oldState: Bool = UIView.areAnimationsEnabled
UIView.setAnimationsEnabled(false)
self.rootViewController = newRootViewController
UIView.setAnimationsEnabled(oldState)
} completion: { _ in
continuation.resume()
}
})
}
}
Crash Occurrence in this method, not regular. Any Idea to fix this sporadic crash..
NSInternalInconsistencyException - Attempting to transfer an animation to an animation state that is not a direct child of the animation's animation state.
Fatal Exception: NSInternalInconsistencyException
0 CoreFoundation 0x92d1c __exceptionPreprocess
1 libobjc.A.dylib 0x14ee4 objc_exception_throw
2 Foundation 0x124c80 _userInfoForFileAndLine
3 UIKitCore 0x5f0658 -[UIViewAnimationState _transferAnimationToTrackingAnimator:]
4 UIKitCore 0x71ee0 __85+[UIViewPropertyAnimator _animationBlockForTrackingAnimation:animator:trackingSetup:]_block_invoke
5 UIKitCore 0x4a3d14 -[UIViewPropertyAnimator _runAnimations]
6 UIKitCore 0x34fba4 __49-[UIViewPropertyAnimator startAnimationAsPaused:]_block_invoke_2
7 UIKitCore 0x206ccc __49-[UIViewPropertyAnimator startAnimationAsPaused:]_block_invoke
8 UIKitCore 0x70754c __49-[UIViewPropertyAnimator startAnimationAsPaused:]_block_invoke.1011
9 UIKitCore 0x510eac -[UIViewPropertyAnimator _setupAnimationTracking:]
10 UIKitCore 0x9c494 -[UIViewPropertyAnimator startAnimationAsPaused:]
11 UIKitCore 0x3396e4 +[UIViewPropertyAnimator _trackAnimationWithAnimator:forLayer:forAnimationKey:trackingSetup:]
12 UIKitCore 0x9c07c +[UIViewPropertyAnimator _trackNonAdditiveAnimationWithAnimator:forLayer:forKey:]
13 UIKitCore 0x58d55c -[UIViewAnimationState pop]
14 UIKitCore 0x25bdb8 +[UIViewAnimationState popAnimationState]
15 UIKitCore 0x1751a8 +[UIView _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:]
Nice method!, thanks