如何使用故事板呈现启动/登录视图控制器 [英] How to present a splash/login view controller using storyboards
问题描述
我在没有明确答案的情况下以各种形式看到了这个问题。我要在这里问一下这个问题。我的应用程序需要在启动时工作... inits,一些网络调用,登录等。我不希望我的主视图控制器工作,直到完成。这样做的好方法是什么?
I've seen this question in various forms without a clear answer. I'm going to ask and answer here. My app needs to do work on startup... inits, a few network calls, login, etc. I don't want my main view controller working until that's done. What's a good pattern for doing this?
要求:
- iOS5 +,故事板,ARC。
- 主要的vc视图在启动工作完成之前不会出现。
- 想要选择过渡样式到主vc时启动工作已经完成。
- 想在storyboard中尽可能多地进行布局。
- 代码应该干净地包含在显而易见的地方。
- iOS5+, storyboards, ARC.
- the main vc's view cannot appear until the startup work is done.
- want a choice of transition styles to the main vc when the startup work is done.
- want to do as much layout as possible in storyboard.
- the code should be cleanly contained somewhere obvious.
推荐答案
编辑,2017年7月
自第一次写作以来,我已将我的练习改为将我的启动任务交给他们自己的视图控制器。在那个VC中,我检查启动条件,如果需要,提供忙UI等。根据启动时的状态,我设置窗口的根VC。
EDIT, July 2017 Since the first writing, I've changed my practice to one where I give the start up tasks to their own view controller. In that VC, I check startup conditions, present a "busy" UI if needed, etc. Based on the state at startup, I set the window's root VC.
In除了解决OP问题之外,这种方法还具有更好地控制启动UI和UI转换的额外好处。以下是如何操作:
In addition to solving the OP problem, this approach has the additional benefits of giving better control of the startup UI and UI transitions. Here's how to do it:
在主故事板中,添加一个名为 LaunchViewController
的新VC并将其设为应用程序的初始vc。为您的应用程序的真实初始vc提供一个标识符,如AppUI(标识符位于IB中的标识选项卡上)。
In your main storyboard, add a new VC, called LaunchViewController
and make it the app's initial vc. Give your app's "real" initial vc an identifier like "AppUI" (identifiers are on the Identity tab in IB).
识别作为主UI启动的其他vcs流程(例如注册/登录,教程等)并提供这些描述性标识符。 (有些人喜欢将每个流程保留在自己的故事板中。这是一个很好的做法,IMO)。
Identify other vcs that are the starts of main UI flows (e.g. Signup/Login, Tutorial, and so on) and give these descriptive identifiers, too. (Some prefer to keep each flow in it's own storyboard. That's a good practice, IMO).
另一个不错的可选想法:给你app的启动故事板的vc也是一个标识符(比如LaunchVC),这样你就可以抓住它并在启动时使用它的视图。这将为用户在启动期间和执行启动任务时提供无缝体验。
One other nice optional idea: give your app's launch storyboard's vc an identifier, too (like "LaunchVC"), so that you can grab it and use it's view during startup. This will provide a seamless experience for the user during launch and while you do your startup tasks.
这是我的 LaunchViewController
看起来像....
Here's what my LaunchViewController
looks like....
@implementation LaunchViewController
- (void)viewDidLoad {
[super viewDidLoad];
// optional, but I really like this:
// cover my view with my launch screen's view for a seamless start
UIStoryboard *storyboard = [self.class storyboardWithKey:@"UILaunchStoryboardName"];
UINavigationController *vc = [storyboard instantiateViewControllerWithIdentifier:@"LaunchVC"];
[self.view addSubview:vc.view];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self hideBusyUI];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self showBusyUI];
// start your startup logic here:
// let's say you need to do a network transaction...
//
[someNetworkCallingObject doSomeNetworkCallCompletion:^(id result, NSError *error) {
if (/* some condition */) [self.class presentUI:@"AppUI"];
else if (/* some condition */) [self.class presentUI:@"LoginUI"];
// etc.
}];
}
#pragma mark - Busy UI
// optional, but maybe you want a spinner or something while getting started
- (void)showBusyUI {
// in one app, I add a spinner on my launch storyboard vc
// give it a tag, and give the logo image a tag, too
// here in animation, I fade out the logo and fade in a spinner
UIImageView *logo = (UIImageView *)[self.view viewWithTag:32];
UIActivityIndicatorView *aiv = (UIActivityIndicatorView *)[self.view viewWithTag:33];
[UIView animateWithDuration:0.5 animations:^{
logo.alpha = 0.0;
aiv.alpha = 1.0;
}];
}
- (void)hideBusyUI {
// an animation that reverses the showBusyUI
}
#pragma mark - Present UI
+ (void)presentUI:(NSString *)identifier {
UIStoryboard *storyboard = [self storyboardWithKey:@"UIMainStoryboardFile"];
UINavigationController *vc = [storyboard instantiateViewControllerWithIdentifier:identifier];
UIWindow *window = [UIApplication sharedApplication].delegate.window;
window.rootViewController = vc;
// another bonus of this approach: any VC transition you like to
// any of the app's main flows
[UIView transitionWithView:window
duration:0.3
options:UIViewAnimationOptionTransitionCrossDissolve
animations:nil
completion:nil];
}
+ (UIStoryboard *)storyboardWithKey:(NSString *)key {
NSBundle *bundle = [NSBundle mainBundle];
NSString *storyboardName = [bundle objectForInfoDictionaryKey:key];
return [UIStoryboard storyboardWithName:storyboardName bundle:bundle];
}
@end
原始答案下面,虽然我更喜欢我当前的方法
让我们表达应用程序准备好用布尔运行主vc,如:
Let's express the app's readiness to run the main vc with a boolean, something like:
BOOL readyToRun = startupWorkIsDone && userIsLoggedIn;
- 创建一个AppStartupViewController并将其放在app storyboard中。
- 不要将任何segue拖到它上面,也不要让它成为盯着vc,只是让它漂浮在某个地方。
- 在故事板中的vc属性检查器中,将其标识符设置为AppStartupViewController。
在AppStartupViewController.m中,当满足readyToRun条件时,它可以解除自身:
In the AppStartupViewController.m, when the readyToRun conditions have been met, it can dismiss itself:
self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; // your choice here from UIModalTransitionStyle
[self dismissViewControllerAnimated:YES completion:nil];
现在,只要应用程序变为活动状态,它就可以检查是否准备好运行,并提供AppStartupViewController这是必要的。
在AppDelegate.h中
Now, whenever the app becomes active, it can check for readiness to run, and present the AppStartupViewController if it's needed. In AppDelegate.h
- (void)applicationDidBecomeActive:(UIApplication *)application {
BOOL readyToRun = startupWorkIsDone && userIsLoggedIn;
if (!readyToRun) {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
AppStartupViewController *startupVC = [storyboard instantiateViewControllerWithIdentifier:@"AppStartupViewController"];
[self.window.rootViewController presentViewController:startupVC animated:NO completion:nil];
// animate = NO because we don't want to see the mainVC's view
}
}
这主要是答案,但有一个障碍。不幸的是,在呈现AppStartupViewController之前,主vc被加载(没关系)并获得viewWillAppear:消息(不行)。这意味着我们必须在MainViewController.m中传播一些额外的启动逻辑,如下所示:
That's mostly the answer, but there is one hitch. Unfortunately the main vc gets loaded (that's okay) and gets a viewWillAppear: message (not okay) before the AppStartupViewController is presented. It means we have to spread a little extra startup logic, like this, in MainViewController.m:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (readyToRun) {
// the view will appear stuff i would have done unconditionally before
}
}
我希望这会有所帮助。
这篇关于如何使用故事板呈现启动/登录视图控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!