如何使用故事板呈现启动/登录视图控制器 [英] How to present a splash/login view controller using storyboards

查看:27
本文介绍了如何使用故事板呈现启动/登录视图控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我以各种形式看到过这个问题,但没有明确的答案.我要在这里提问和回答.我的应用程序需要在启动时工作......初始化、一些网络调用、登录等.我不希望我的主视图控制器在完成之前工作.这样做的好模式是什么?

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 的过渡样式.
  • 希望在故事板中尽可能多地进行布局.
  • 代码应该清楚地包含在明显的地方.

推荐答案

编辑,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.

除了解决 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 流程开始的其他 vc(例如注册/登录、教程等)并给出这些描述性标识符.(有些人更喜欢将每个流程保留在自己的故事板中.这是一个很好的做法,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).

另一个不错的可选想法:也为您的应用程序的启动故事板的 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;

  1. 创建一个 AppStartupViewController 并将其布置在应用故事板中.
  2. 不要将任何 segue 拖到它上面,也不要使它成为凝视的 vc,只需让它漂浮在某处即可.
  3. 在故事板中 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
    }
}

这就是答案,但有一个问题.不幸的是,主 vc 被加载(没关系)并在 AppStartupViewController 出现之前获得一个 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆