如何设置新的根视图控制器
Posted
技术标签:
【中文标题】如何设置新的根视图控制器【英文标题】:How to set a new root view controller 【发布时间】:2016-01-27 05:39:55 【问题描述】:我想知道是否可以设置一个新的根VC?
我的应用使用 uinavigation 控制器进行初始化,该控制器具有作为根 VC 的表视图。
然后从表格视图中,我正在运行另一个登录窗口(以模态方式显示)如果您随后登录,您最终会进入 red VC/帐户页面。我现在要做的是将红色 VC 设置为应用程序的新根 VC,并删除所有底层 VC。这样我就可以显示菜单按钮/图标而不是“返回”按钮
我找到了这个,但我不明白如何使用它:
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let yourViewController: ViewController = storyboard.instantiateViewControllerWithIdentifier("respectiveIdentifier") as! ViewController
let navigationController = self.window?.rootViewController as! UINavigationController
navigationController.setViewControllers([yourViewController], animated: true)
但我无法让它工作。那么是否可以让图中红色的vc作为新的根VC呢?
【问题讨论】:
【参考方案1】:斯威夫特 4.2
也许你应该试试这个
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let redViewController = mainStoryBoard.instantiateViewController(withIdentifier: "respectiveIdentifier") as! ViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = redViewController
【讨论】:
好吧...它不会崩溃。但对我来说,这里什么都没有发生。不会加载新视图 我的问题是新的视图控制器替换了旧的。但是仍然保留视图控制器堆栈。不知道那些视图控制器堆栈来自哪里。 使用SceneDelegate的人请参考***.com/questions/56588843/…【参考方案2】:Swift 4、5、5.1
let story = UIStoryboard(name: "Main", bundle:nil)
let vc = story.instantiateViewController(withIdentifier: "NewViewController") as! NewViewController
UIApplication.shared.windows.first?.rootViewController = vc
UIApplication.shared.windows.first?.makeKeyAndVisible()
【讨论】:
非常感谢。 !!这对我有很大帮助。 makeKeyAndVisible 可以解决问题!谢谢 非常感谢【参考方案3】:Swift 3 更新:-
let testController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "testController") as! TestController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = testController
【讨论】:
为我工作谢谢 这不会从下面删除以前的视图...【参考方案4】:斯威夫特 4 答案
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "YourViewController") as! YourViewController
let navigationController = UINavigationController(rootViewController: nextViewController)
let appdelegate = UIApplication.shared.delegate as! AppDelegate
appdelegate.window!.rootViewController = navigationController
【讨论】:
如何用导航栏实例化根视图控制器...我不明白 在xcode 11中做什么。appdelegate中没有window属性【参考方案5】:UINavigationController 有一个 viewControllers 属性,它是一个 NSArray,你可以用你自己的视图控制器的 NSArray 替换它。
这可以通过下面的示例代码来完成。
let newViewController = self.storyboard?.instantiateViewControllerWithIdentifier("YourViewControllerollerID") as! YourViewController
let customViewControllersArray : NSArray = [newViewController]
navigationController?.viewControllers = customViewControllersArray as! [UIViewController]
如果你想展示这个新的根视图控制器,你可以调用 UINavigationController 的 popToRootViewController() 方法。
navigationController?.popToRootViewControllerAnimated(true)
【讨论】:
【参考方案6】:为了让原始问题中的代码 sn-p 正常工作,我不得不对第三行进行更改
let navigationController = self.navigationController!
我在新根视图控制器之前的视图控制器中的@IBAction 中使用此代码。
使用原始代码时,我收到一条错误消息,指出我的视图控制器没有名为 window
的成员。查看documentation 后,我找不到名为window
的属性。我想知道上面的原始代码块是否打算在UINavigationController
文件中使用。
这是整个区块。
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let todayViewController: TodaysFrequencyViewController = storyboard.instantiateViewControllerWithIdentifier("todaysFrequency") as! TodaysFrequencyViewController
let navigationController = self.navigationController!
navigationController.setViewControllers([todayViewControl ler], animated: true)
【讨论】:
【参考方案7】:我想知道是否可以设置一个新的根VC?
是的,这是可能的。你怎么做取决于上下文......
我的应用使用 uinavigation 控制器进行初始化,该控制器具有作为根 VC 的表视图。
实际上有两个东西通常被称为“根视图控制器”:
UIWindow
有一个可写的rootViewController
属性。
UINavigationController
没有rootViewController
属性,但它确实有一个名为-initWithRootViewController:
的初始化程序。您可以设置导航控制器的“根”视图控制器,方法是设置它的 viewControllers
属性。
听起来您正在尝试更改窗口的根视图控制器,但您显示的代码仅更改了导航控制器的 viewControllers
属性。尝试直接设置窗口的rootViewController
属性。但是,请理解,如果您采用这种方法,那么导航控制器也会消失。另一方面,如果您想保留导航控制器,请采用您当前的方法。
但我无法让它工作。那么是否可以让图中红色的vc作为新的根VC呢?
此处提供更多信息会有所帮助。 “无法正常工作”是什么意思?会发生什么,您预计会发生什么?
【讨论】:
经过您的解释,我认为我应该更改窗口根目录。但是如果我这样做,我可以添加一个新的 uinavigation 控制器并删除所有旧视图吗?例如 VC 由模态 segue 打开 在故事板中,我还检查了导航控制器上的“是初始 VC” 可以,但是如果您的导航控制器已经是窗口的根视图控制器,并且如果您想要导航控制器并且不需要当前的视图控制器堆栈,那么为什么不保留导航控制器你有? IOW,您当前的方法是合理的——如果它不起作用,您应该提供更多信息。你怎么知道它不起作用?navigationController.viewControllers
设置后会显示什么?
我收到错误“MyViewController”没有名为视图的成员。在转换到应该成为新根的新 VC 时,我应该在哪里/如何准确地实现代码?
每个视图控制器都有一个view
属性,因此如果您收到该消息,则您正在发送消息的对象不是正确的视图控制器。首先确保您的 ViewController
类派生自 UIViewController
。【参考方案8】:
对于 swift 4.0。
在 didfinishedlaunchingWithOptions 方法的 AppDelegate.swift 文件中,输入以下代码。
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let rootVC = MainViewController() // your custom viewController. You can instantiate using nib too. UIViewController(nib name, bundle)
let navController = UINavigationController(rootViewController: rootVC) // Integrate navigation controller programmatically if you want
window?.rootViewController = navController
return true
希望它能正常工作。
【讨论】:
【参考方案9】:您可以在单击登录按钮时使用此代码:-
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var vc = mainStoryboard.instantiateViewControllerWithIdentifier("respectiveIdentifier") as ViewController
UIApplication.sharedApplication().keyWindow.rootViewController = vc
【讨论】:
【参考方案10】:你可以使用这段代码:
let newViewController = self.storyboard?.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
let customViewControllersArray : NSArray = [newViewController]
self.navigationController?.viewControllers = customViewControllersArray as! [UIViewController]
self.navigationController?.pushViewController(newViewController, animated: true)
【讨论】:
您能解释一下为什么您的代码有助于回答 OP 的问题吗? 如果 HomeViewController 是您的根视图控制器,那么您可以使用 pushViewController 将其设置为根视图控制器【参考方案11】:如果需要给rootViewController设置一些动画,代码如下:
guard let window = UIApplication.shared.keyWindow else
return
guard let rootViewController = window.rootViewController else
return
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "MainTabbar")
vc.view.frame = rootViewController.view.frame
vc.view.layoutIfNeeded()
UIView.transition(with: window, duration: 0.3, options: .transitionCrossDissolve, animations:
window.rootViewController = vc
, completion: completed in
// maybe do something here
)
【讨论】:
【参考方案12】:对于 Swift 5 用户,您可以这样做,这绝对适合您。
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
manageLoginSession()
guard let _ = (scene as? UIWindowScene) else return
func manageLoginSession()
guard let window = window else return
if UserDefaults.standard.bool(forKey: "_key_AlreadyLogin") == true
window.rootViewController = UIStoryboard(name: "Dashboard", bundle: nil).instantiateInitialViewController()
else
window.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
【讨论】:
【参考方案13】:您如何以及从哪里展示 redVC?
您可以将其设为 UINavigationController 的根视图控制器,因此您仍然可以推送和弹出视图控制器。
self.navigationController?.viewControllers = [self];
【讨论】:
【参考方案14】:一旦你进入了你想设置为root的vc,只需添加你的viewDidLoad:
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = self
*根据最佳实践,您应该检查它是否已经是根,如果不是,则执行上面的代码。
【讨论】:
【参考方案15】:斯威夫特 3 AppDelegate 文件:::
@IBAction func btnGoBack(_ sender: UIButton)
self.goToHomeVC()
func goToHomeVC()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier :"HomeVC") as! HomeVC
let navController = UINavigationController.init(rootViewController: viewController)
if let window = self.appDelegate.window, let rootViewController = window.rootViewController
var currentController = rootViewController
while let presentedController = currentController.presentedViewController
currentController = presentedController
currentController.present(navController, animated: true, completion: nil)
【讨论】:
【参考方案16】:你可以试试这个代码
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
【讨论】:
【参考方案17】:任何你想设置根的视图控制器只需调用下面的函数就像
UIApplication.shared.setRootVC(vc)
extension UIApplication
func setRootVC(_ vc : UIViewController)
self.windows.first?.rootViewController = vc
self.windows.first?.makeKeyAndVisible()
【讨论】:
【参考方案18】:只要写下这个,你就可以开始了。
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)
【讨论】:
请解释为什么这样做。问题是什么以及为什么会解决它。 UInavigationController 有一个属性允许用户设置它的根视图控制器,所以在这里我们将我们的 VC 设置为当前导航堆栈的顶部,并使其成为根视图控制器【参考方案19】:这就是您可以将 nib 设置为根视图控制器的方法。
let vc = HomeViewController(nibName: "HomeViewController", bundle: nil)
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = vc
window?.makeKeyAndVisible()
【讨论】:
【参考方案20】:Link to a related question
此答案适用于从当前堆栈中的某处使用现有 ViewController,而无需实例化和重新配置新控制器。
文档说:根视图控制器提供窗口的内容视图。将视图控制器分配给该属性(以编程方式或使用 Interface Builder)将视图控制器的视图安装为窗口的内容视图。新的内容视图被配置为跟踪窗口大小,随着窗口大小的变化而变化。 如果窗口具有现有的视图层次结构,则在安装新视图之前会删除旧视图。
正如文档所说:如果 rootViewController 被交换,它会删除堆栈中的所有视图。 不管控制器是什么。所以从堆栈中移除 ViewController 以确保它的视图不会被移除。
这导致了我在以下解决方案中的情况:
if let appDelegate = UIApplication.shared.delegate as? AppDelegate
guard let pageVC = self.onboardingDelegate as? OnboardingPageViewController else return // my current stack is in a pageViewController, it also is my delegate
let vc = self // holding myself
pageVC.subViewControllers.removeLast() // removing myself from the list
pageVC.setViewControllers([pageVC.subViewControllers[0]], direction: .forward, animated: false, completion: nil) // remove the current presented VC
appDelegate.window?.rootViewController = vc
vc.onboardingDelegate = nil
appDelegate.window?.makeKeyAndVisible()
【讨论】:
【参考方案21】:斯威夫特 4
let storyBoard = UIStoryboard(name: "Your_Storyboard_Name", bundle:Bundle.main)
self.window = UIWindow(frame: UIScreen.main.bounds)
let yourVc = storyBoard.instantiateViewController(withIdentifier: "YourIdentifier") as? YourViewController
if let window = window
window.rootViewController = yourVc
window?.makeKeyAndVisible()
【讨论】:
【参考方案22】:Swift 4,5 及以上 如果您使用多个或单个故事板,您想设置导航控制器的不同根视图控制器,那么我使用此方法: 在我的情况下,StoryBaord 名称是 Auth。
func setRootToLogin(transition :CATransition)
let storyboard = UIStoryboard(name: "Auth", bundle: nil)
let loginNav = storyboard.instantiateViewController(withIdentifier: "AuthNavigationController") as! UINavigationController
window.set(rootViewController: loginNav, withTransition: transition)
let vc = window.rootViewController as! UINavigationController
let loginvc = LoginViewController.instantiateAuth()
vc.setViewControllers([loginvc], animated: true)
【讨论】:
以上是关于如何设置新的根视图控制器的主要内容,如果未能解决你的问题,请参考以下文章
在我添加了一个新的初始 UIViewController 之后,UINavigationController “表现得很疯狂”