如何设置新的根视图控制器

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)

【讨论】:

以上是关于如何设置新的根视图控制器的主要内容,如果未能解决你的问题,请参考以下文章

如何使用给定的根视图控制器和初始视图控制器实例化情节提要?

UINavigation的外观设置和页面之间的跳转

在我添加了一个新的初始 UIViewController 之后,UINavigationController “表现得很疯狂”

如何传递int的数据?

应用程序启动结束时的根视图控制器,默认为 cocos2d 视图控制器而不是另一个故事板视图

如何将新的 viewController 推送到另一个视图控制器中的现有视图中?