Ios 在应用程序启动时以模式显示视图控制器
我的应用程序有一个设置屏幕,如果满足某些条件,该屏幕应以模式显示在根视图控制器上 我已经在SO和互联网上四处查看过,到目前为止,最接近的答案是: 然而,这种方法存在两个问题:Ios 在应用程序启动时以模式显示视图控制器,ios,objective-c,Ios,Objective C,我的应用程序有一个设置屏幕,如果满足某些条件,该屏幕应以模式显示在根视图控制器上 我已经在SO和互联网上四处查看过,到目前为止,最接近的答案是: 然而,这种方法存在两个问题: 在iOS 8中,这样做会在控制台中显示日志,这似乎不是错误,但可能并不好: 对UITabBarController的开始/结束外观转换的不平衡调用:0x7fe20058d570。 当应用程序启动时,根视图控制器实际上会短暂显示,然后淡入显示的视图控制器(即使我在我的presentViewController方法中显式调用
对UITabBarController的开始/结束外观转换的不平衡调用:0x7fe20058d570。
presentViewController
方法中显式调用animated:NO
)ApplicationIDFinishLaunchingWithOptions:
中动态设置我的根控制器,但我特别想以模式显示设置屏幕,这样当用户使用完它时,它就会消失,并显示应用程序的真实第一视图。这就是说,我不想动态地将我的根视图控制器更改为我的设置屏幕,并在用户完成设置后以模式呈现我的应用体验
在我的根视图控制器viewDidLoad
方法上显示视图控制器也会导致应用程序第一次启动时UI出现明显的闪烁
在应用程序呈现任何内容之前,是否可以通过编程方式以模态方式呈现视图控制器,以便第一个视图是模态视图控制器
更新:感谢您的评论,按照建议添加我当前的代码:
在myAppDelegate.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;
}
这就是我所需要的,只是当应用程序启动时,它会短暂地显示窗口的根视图控制器一秒钟,然后淡出setupViewController,我觉得这很奇怪,因为我在没有动画的情况下呈现它,淡出并不是模态视图控制器的呈现方式
唯一让我接近的是在根视图控制器的view Dod load方法中手动添加视图,如下所示:
- (void)viewDidLoad
{
[self.view addSubview:setupViewController.view];
[self addChildViewController:setupViewController];
}
这种方法的问题是,我不能再“本机”关闭setupViewController,现在需要自己处理视图层次结构并设置动画,如果这是唯一的解决方案,这很好,但我希望有一种被认可的方式,在根视图控制器显示之前,在没有动画的情况下添加视图控制器
更新2:在尝试了很多东西并等待了2个月的答案后,这个问题提出了最有创意的解决方案:
我想是时候接受这一点了,即在根视图控制器出现之前,不可能以无动画的方式呈现视图。但是,该线程中的建议是创建启动屏幕的实例,并将其保持在比默认值更长的时间,直到模态视图控制器有机会显示自己
我知道我可以在ApplicationIDFinishLaunchingWithOptions中动态设置我的根控制器:但我特别希望以模式显示设置屏幕,这样当用户使用完它时,它就会消失,并显示应用程序的真实第一视图
我有两个建议。一种是尝试在viewdide:
中执行此操作。我试过了,虽然如果仔细观察,您确实可以看到根视图控制器的视图,但您几乎看不到它,有时如果眨眼,您根本看不到它:
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self presentViewController:[self.storyboard instantiateViewControllerWithIdentifier:@"setupViewController"] animated:NO completion:NULL];
}
当然,您需要添加一个标志,这样您就不会在每次调用viewdide:
时都这样做,否则您将永远无法回到这个视图控制器!但这是微不足道的,我把它留给读者作为练习
我的另一个建议是使用自定义的嵌入式(子)视图控制器,而您显然已经考虑过这样做。这就绕过了整个“演示”的局限性
正如您所说,我会动态地启动和设置事物,如果需要的话,在子视图控制器存在的情况下,在启动过程中对其进行配置。子视图控制器的视图只覆盖根视图控制器的视图。这就是用户在应用程序启动时所看到的
然后,当用户的设置过程结束并且用户“取消”该视图时,您可以通过动画将该视图向下撕下,并移除子视图控制器-下面显示根视图控制器的视图。动画将使这一切与当前视图的取消无法区分,即使它不是一个真正的视图。我和你在同一条船上,找到了相同的答案。我了解到,通过将setupViewController的
modalPresentationStyle
设置为.OverCurrentContext
或.OverFullScreen
,可以解决第一个问题(不平衡呼叫警告)。问题解决了——所以我想
直到后来我才注意到第二个问题,那是我无法忍受的。。。回到原点
正如你所说,我想要一个具有普通视图层次结构的解决方案,我不想“伪造”某些东西。我认为最优雅的解决方案是在第一次解雇setupViewController时切换windows rootViewController
因此,在启动时,可以将setupViewController设置为rootViewController(如果需要):
安装完成后,在appDelegate中调用一个方法以切换到“real”rootViewController:
func switchToTabBarController() {
let setupUpViewController = window!.rootViewController!
tabBarController.view.frame = window!.bounds
window!.insertSubview(tabBarController.view, atIndex: 0)
let height = setupUpViewController.view.bounds.size.height
UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1, options: .allZeros, animations: { () -> Void in
setupUpViewController.view.transform = CGAffineTransformMakeTranslation(0, height)
}) { (completed) -> Void in
self.window!.rootViewController = self.tabBarController
}
}
我在看一部“封面垂直”的动画。对于crossfade和其他,您可以使用UIView.transitionFromView(fromView:UIView,toView:UIView…)
。此后,您可以以正常方式显示/关闭setupController,因此您的doneButton操作可能如下所示:
@IBAction func doneButtonSelected(sender: UIButton) {
if presentingViewController != nil {
presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
} else {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.switchToTabBarController()
}
}
事实上,我是
@IBAction func doneButtonSelected(sender: UIButton) {
if presentingViewController != nil {
presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
} else {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.switchToTabBarController()
}
}
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()
})
}
}