以编程方式使用 UINavigationController 设置 RootViewController

Posted

技术标签:

【中文标题】以编程方式使用 UINavigationController 设置 RootViewController【英文标题】:Setting a RootViewController with UINavigationController Programmatically 【发布时间】:2015-02-11 15:11:52 【问题描述】:

我有一个带有导航控制器和默认 RootViewController 的程序。如果我不以编程方式执行任何操作,应用程序就会启动并且 RootViewController 会按我的预期工作,例如下面的情节提要:

我遇到的问题是通过合并可选的 Start ViewController。我想要的是:在我的 AppDelegate (didFinishLaunchingWithOptions) 中,我想要这样的代码:

UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"OptionalStartViewController"];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];

首先显示可选的启动 ViewController。然后,在用户完成了 Optional viewcontroller 之后,他们就可以显示 RootViewController。

所以在 Optional Start ViewController 中,我添加了这样的代码来显示根视图控制器:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil];
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"RootViewController"];
[self appDelegate].window.rootViewController = viewController;
[[self appDelegate].window makeKeyAndVisible];

这一切都有效除了 RootViewController,当显示时,没有预期的导航控件(即视图显示时没有导航控件)。

我也尝试了下面的代码(使用 UINavigationController 而不是 ViewController),结果相同...

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil];
UINavigationController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"HomeViewController"];
[self appDelegate].window.rootViewController = viewController;
[[self appDelegate].window makeKeyAndVisible];

另一个转折……可能有几个可选的开始视图控制器。

有什么想法吗?

【问题讨论】:

那么问题是导航栏不存在? 使用UINavigationController的标识符而不是UIViewController(根视图控制器)。 将 UINavigationController 设置为 root 确实对我有用。 @gabbler...你是不是先设置了一个不同的viewcontroller作为rootviewcontroller,然后再显示你实际的rootviewcontroller?你的代码是什么样的? 在我的故事板中,我将可选的视图控制器设置为根,在这个可选的视图控制器中,我单击了一个按钮来显示导航控制器,它起作用了。 【参考方案1】:
    删除UINavigationController 选择控制器(在我们的例子中是“可选的启动视图控制器”) 点击Editor >> Embed In >> Navigation Controller 现在选择Navigation Controller 和右侧实用程序区域,选择选项Is Initial View Controller

如果您想动态更改根视图控制器,那么最好以编程方式进行,在didFinishLaunchingWithOptions 中,获取窗口实例,使用根视图控制器初始化导航控制器,然后将窗口根视图控制器设置为导航控制器。 这是代码。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
// Override point for customization after application launch.

    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

    OptionalFirstViewController *optionalFirstViewController = [[OptionalFirstViewController alloc] initWithNibName:@"OptionalFirstViewController" bundle:nil];
    UINavigationController *homeNavigationController = [[UINavigationController alloc] initWithRootViewController:optionalFirstViewController];
    [optionalFirstViewController release];
    self.window.rootViewController = homeNavigationController;
    [homeNavigationController release];
    [self.window makeKeyAndVisible];

    return YES;

并确保为故事板中的所有视图控制器取消选中 Is Initial View Controller

希望对你有帮助

【讨论】:

如果有多个可选的启动视图控制器怎么办? 好吧,那么您只需要事先决定要显示哪个并使用它。这增加了上述代码的业务规则的复杂性。 是的,当然你需要事先知道根据你的业务逻辑显示哪个控制器,你总是可以将业务逻辑保存在一个单独的类/方法中,它返回一个类名,在这里你可以初始化所需的控制器。这只是在上面的代码中增加了一行。【参考方案2】:

不使用故事板我们可以在AppDelegate类中编程设置,只需在AppDelegate中写下这些代码行。

AppDelegate.h

@property (strong, nonatomic) UIStoryboard *storyboard;
@property (strong, nonatomic) UINavigationController *navigationController;

AppDelegate.m

if(self.window == nil)
    self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];

if(self.navigationController == nil)
    self.navigationController = [[UINavigationController alloc]init];

if(self.storyboard == nil)
    self.storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];

self.navigationController.navigationBarHidden = YES;

// Here we can check user is login or not also,

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ViewController *ivc = [storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
[self.navigationController pushViewController:ivc animated:YES];
self.window.rootViewController = ivc;


[self.window setRootViewController:self.navigationController];
[self.window makeKeyAndVisible];

Swift 版本中

var window: UIWindow?
var storyBoard :UIStoryboard?
var navigationController : UINavigationController?
var mainController :MainViewController = MainViewController()

if window == nil 
        window = UIWindow(frame: UIScreen.main.bounds)
    
    if navigationController == nil 
        navigationController = UINavigationController()
    
    if storyBoard == nil 
        storyBoard = UIStoryboard(name: "Main", bundle:nil)
    
    navigationController?.setNavigationBarHidden(true, animated: true)
    // storyboard with identifer
    mainController = storyBoard?.instantiateViewController(withIdentifier: "MainViewController") as! MainViewController
    navigationController?.pushViewController(mainController , animated: true)

    window?.rootViewController = navigationController
    window?.makeKeyAndVisible()

【讨论】:

【参考方案3】:

初始化后,您不能将新的根视图控制器设置为UINavigationController。您应该根据需要修改UINavigationControllerviewControllers 数组。

如果您希望可选 VC 为根 VC,请创建 @[optionalVC] 并将其设置为 UINavigationControllerviewControllers 数组。

【讨论】:

以上是关于以编程方式使用 UINavigationController 设置 RootViewController的主要内容,如果未能解决你的问题,请参考以下文章

为啥我没有成功以编程方式使用 segue?

以编程方式添加视图与使用 recyclerView 有啥区别?

使用 swift 以编程方式 UITableView

为啥文本字段委托不能以编程方式在文本字段上使用设置文本?

在 Windows 中以编程方式确定电源使用情况?

如何使用 c# 检查 OpenOffice 是不是以编程方式安装