Ann*_*nna 62 ios rootviewcontroller
iOS窗口的根视图控制器通常在开始时一次初始化为标签栏控制器或导航控制器吗?在应用程序中多次更改根视图控制器是否可以?
我有一个场景,根据用户操作,顶视图是不同的.我想到的是一个导航控制器,顶视图控制器具有启动画面的图像,并根据需要推/弹视图控制器.或者,我可以继续更改窗口的顶视图控制器.哪种方法更好?
ser*_*e-k 50
iOS 8.0,Xcode 6.0.1,ARC启用
大多数问题都得到了解答.但是,我可以解决一个我最近不得不处理的问题.
在应用程序中多次更改根视图控制器是否可以?
答案是肯定的.最近我必须在最初的UIViews之后重置我的UIView层次结构,这是应用程序的一部分.不再需要启动.换句话说,您可以在应用程序之后随时从任何其他UIViewController重置"rootViewController"."didFinishLoadingWithOptions".
去做这个...
1)声明对您的应用的引用.委托(app称为"测试")......
TestAppDelegate *testAppDelegate = (TestAppDelegate *)[UIApplication sharedApplication].delegate;
2)选择一个你希望制作"rootViewController"的UIViewController; 无论是从故事板还是以编程方式定义......
UIStoryboard *mainStoryBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
NewRootViewController *newRootViewController = [mainStoryBoard instantiateViewControllerWithIdentifier:@"NewRootViewController"];
UIViewController *newRootViewController = [[UIViewController alloc] init];
newRootViewController.view = [[UIView alloc] initWithFrame:CGRectMake(0, 50, 320, 430)];
newRootViewController.view.backgroundColor = [UIColor whiteColor];
3)把它们放在一起......
 testAppDelegate.window.rootViewController = newRootViewController;
[testAppDelegate.window makeKeyAndVisible];
4)你甚至可以投入动画......
testAppDelegate.window.rootViewController = newRootViewController;
    [testAppDelegate.window makeKeyAndVisible];
newRootViewController.view.alpha = 0.0;
    [UIView animateWithDuration:2.0 animations:^{
        newRootViewController.view.alpha = 1.0;
    }];
希望这有助于某人!干杯.
窗口的根视图控制器.
根视图控制器提供窗口的内容视图.将视图控制器分配给此属性(以编程方式或使用Interface Builder)将视图控制器的视图安装为窗口的内容视图.如果窗口具有现有视图层次结构,则在安装新视图之前将删除旧视图.此属性的默认值为nil.
*2015年9月2日更新
正如下面的注释所指出的,您必须在呈现新视图控制器时处理旧视图控制器的删除.您可以选择使用过渡视图控制器来处理此问题.以下是有关如何实现此功能的一些提示:
[UIView transitionWithView:self.containerView
                  duration:0.50
                   options:options
                animations:^{
                    //Transition of the two views
                    [self.viewController.view removeFromSuperview];
                    [self.containerView addSubview:aViewController.view];
                }
                completion:^(BOOL finished){
                    //At completion set the new view controller.
                    self.viewController = aViewController;
                }];
mat*_*att 47
更常见的是使用"呈现的视图控制器"(presentViewController:animated:completion:).您可以根据需要拥有尽可能多的这些,有效地出现在(并且基本上替换)根视图控制器之前.如果你不想要,或者有可能,就没有任何动画.您可以关闭呈现的视图控制器以返回到原始根视图控制器,但您不必; 如果您愿意,所呈现的视图控制器可以永远存在.
这是我书中提供的视图控制器部分:
http://www.apeth.com/iOSBook/ch19.html#_presented_view_controller
在该图中(从该章的前面开始),呈现的视图控制器已经完全接管了应用程序界面; 根视图控制器及其子视图不再在界面中.根视图控制器仍然存在,但这是轻量级的并不重要.

Mat*_*čík 37
根据对serge-k的回答的评论,当有一个模态视图控制器呈现在旧的rootViewController上时,我已经构建了一个工作解决方案,其中包含奇怪行为的解决方法:
extension UIView {
    func snapshot() -> UIImage {
        UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.mainScreen().scale)
        drawViewHierarchyInRect(bounds, afterScreenUpdates: true)
        let result = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return result
    }
}
extension UIWindow {
    func replaceRootViewControllerWith(_ replacementController: UIViewController, animated: Bool, completion: (() -> Void)?) {
        let snapshotImageView = UIImageView(image: self.snapshot())
        self.addSubview(snapshotImageView)
        let dismissCompletion = { () -> Void in // dismiss all modal view controllers
            self.rootViewController = replacementController
            self.bringSubview(toFront: snapshotImageView)
            if animated {
                UIView.animate(withDuration: 0.4, animations: { () -> Void in
                    snapshotImageView.alpha = 0
                }, completion: { (success) -> Void in
                    snapshotImageView.removeFromSuperview()
                    completion?()
                })
            }
            else {
                snapshotImageView.removeFromSuperview()
                completion?()
            }
        }
        if self.rootViewController!.presentedViewController != nil {
            self.rootViewController!.dismiss(animated: false, completion: dismissCompletion)
        }
        else {
            dismissCompletion()
        }
    }
}
要替换rootViewController,只需使用:
let newRootViewController = self.storyboard!.instantiateViewControllerWithIdentifier("BlackViewController")
UIApplication.sharedApplication().keyWindow!.replaceRootViewControllerWith(newRootViewController, animated: true, completion: nil)
希望这有助于:)在iOS 8.4上测试; 还测试了导航控制器支持(还应支持标签栏控制器等,但我没有测试它)
说明
如果在旧的rootViewController上显示模态视图控制器,则替换rootViewController,但旧视图仍然悬挂在新的rootViewController视图下方(并且可以在Flip Horizontal或Cross Dissolve过渡动画期间看到)和旧视图控制器层次结构仍然分配(如果多次更换,可能会导致严重的内存问题).
所以唯一的解决方案是解除所有模态视图控制器,然后替换rootViewController.在解雇和替换期间,屏幕的快照被放置在窗口上以隐藏丑陋的闪烁过程.
您可以在整个应用程序生命周期中更改窗口的rootViewController.
UIViewController *viewController = [UIViewController alloc] init];
[self.window setRootViewController:viewController];
当您更改rootViewController时,您仍可能希望在窗口上添加UIImageView作为子视图以充当启动图像.我希望这是有道理的,像这样:
- (void) addSplash {
    CGRect rect = [UIScreen mainScreen].bounds;
    UIImageView *splashImage = [[UIImageView alloc] initWithFrame:rect];
    splashImage.image = [UIImage imageNamed:@"splash.png"];
    [self.window addSubview:splashImage];
}
- (void) removeSplash {
    for (UIView *view in self.window.subviews) {
      if ([view isKindOfClass:[UIImageView class]]) {
        [view removeFromSuperview];
      }
    }
}