在app启动时以模态方式呈现视图控制器

Fto*_*edo 17 objective-c ios

我的应用程序有一个设置屏幕,如果满足某些条件,应该在根视图控制器上以模态方式显示.

我已经浏览了SO和互联网,到目前为止最接近的答案是如何去做这个:

AppDelegate,rootViewController和presentViewController

但是这种方法存在两个问题:

  1. 在iOS 8中,这样做会使日志显示在控制台中,这似乎不是一个错误,但可能不是很好:

Unbalanced calls to begin/end appearance transitions for UITabBarController: 0x7fe20058d570.

  1. 当应用程序启动时,根视图控制器实际上会非常短暂地显示,然后淡入到呈现的视图控制器中(即使我明确地调用animated:NO了我的presentViewController方法).

我知道我可以动态设置我的根控制器,applicationDidFinishLaunchingWithOptions:但我特别希望以模态方式呈现设置屏幕,这样当用户完成它时,它会解散并显示应用程序的真实第一个视图.这就是说,我不想动态地将我的根视图控制器更改为我的设置屏幕,并在用户完成设置时以模态方式呈现我的应用体验.

在我的根视图控制器viewDidLoad方法上呈现视图控制器也会在第一次启动应用程序时导致UI明显闪烁.

是否有可能在应用程序呈现任何内容之前以编程方式呈现视图控制器,以便第一个视图就位于模态视图控制器中?

更新:感谢您的评论,按照建议添加我当前的代码:

在我的AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];

    [self.window makeKeyAndVisible];
    [self.window.rootViewController presentViewController:[storyboard instantiateViewControllerWithIdentifier:@"setupViewController"] animated:NO completion:NULL];

    return YES;
}
Run Code Online (Sandbox Code Playgroud)

这样做我需要的除了它在应用程序启动时简要显示窗口的根视图控制器一秒钟的事实,然后淡化setupViewController,我发现奇怪的是我提出它没有动画和褪色不是一个模态无论如何都会呈现视图控制器.

让我接近的唯一一件事是在根视图控制器的视图中手动添加视图确实加载方法如下:

- (void)viewDidLoad
{
    [self.view addSubview:setupViewController.view];
    [self addChildViewController:setupViewController];
}
Run Code Online (Sandbox Code Playgroud)

这种方法的问题是我不能再"原生"地关闭setupViewController,现在需要处理视图层次结构并自己动画,如果这是唯一的解决方案,这很好,但我希望有一个在根视图控制器显示之前,在没有动画的情况下以模态方式添加视图控制器的认可方式.

更新2:在尝试了很多事情并等待2个月的答案之后,这个问题提出了最有创意的解决方案:

iOS在没有闪存的情况下启动模态视图控制器

我想是时候接受在根视图控制器出现之前不能在没有动画的情况下以模态方式呈现视图的时候了.但是,该线程中的建议是创建一个启动屏幕的实例,并将其保持为超过默认值,直到模态视图控制器有机会出现.

Cœu*_*œur 10

我想是时候接受在根视图控制器出现之前不能在没有动画的情况下以模态方式呈现视图的时候了.

它出现之前,不,你不能出席.但是有多种有效的方法可以直观地解决这个问题.我推荐下面的解决方案A,因为它简单.

A.将launchScreen添加为子视图,然后显示,然后删除启动画面

解决方案由ullstrm提供,并且不会受到开始/结束外观转换的不平衡调用的影响:

let launchScreenView = UIStoryboard(name: "LaunchScreen", bundle: nil).instantiateInitialViewController()!.view!
launchScreenView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
launchScreenView.frame = window!.rootViewController!.view.bounds
window?.rootViewController?.view.addSubview(launchScreenView)
window?.makeKeyAndVisible()
// avoiding: Unbalanced calls to begin/end appearance transitions.
DispatchQueue.global().async {
    DispatchQueue.main.async {
        self.window?.rootViewController?.present(myViewControllerToPresent, animated: false, completion: {
            launchScreenView.removeFromSuperview()
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

B.首先添加addChildViewController,然后删除,然后呈现

Benedict Cohen在此提出解决方案.


mat*_*att 1

我知道我可以在 applicationDidFinishLaunchingWithOptions: 中动态设置我的根控制器:但我特别想以模态方式呈现设置屏幕,以便当用户完成它时,它会关闭并显示应用程序的真正第一个视图。

我有两个建议。一是尝试在viewDidAppear:. 我尝试了一下,虽然如果你仔细看的话确实会看到根视图控制器的视图,但你几乎看不到它,有时如果你眨眼你根本看不到它:

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self presentViewController:[self.storyboard instantiateViewControllerWithIdentifier:@"setupViewController"] animated:NO completion:NULL];
}
Run Code Online (Sandbox Code Playgroud)

当然,您需要添加一个标志,这样您就不会每次viewDidAppear:调用时都这样做 - 否则您将永远无法返回到此视图控制器!但这是微不足道的,我把它作为练习留给读者。

我的另一个建议 - 您已经明确考虑过这样做 - 是使用自定义嵌入式(子)视图控制器。这解决了整个“演示”问题的局限性。

正如您所说,我会动态启动和设置事物,如果需要,可以使用子视图控制器,在启动过程中配置所有内容。子视图控制器的视图将只覆盖根视图控制器的视图。这就是应用程序启动时用户会看到的内容。

然后,当用户的设置过程结束并且用户“关闭”该视图时,您可以使用动画将该视图撕下来,并删除子视图控制器 - 显示下面的根视图控制器的视图。动画将使这一切与所呈现的视图的消失没有区别,即使它实际上不是一个。