Skip to content

iOS Loading Screen Flash Animation

2011 December 30
by Alec

Edit: I can no longer recommend using a webview in this instance, as there’s no (easy) way to detect when the animation is done playing, at least when using a Swiffy-generated HTML page. Instead, in this instance I converted the flash animation to a .mp4 and used an MPMoviePlayerController rather than a WebView. The splash image implementation remains the same.

I’ve been working on a refresh of the Ski Utah iPhone app and had a specific requirement for an animated loading screen. But like the rest of the platform, Apple has a standardized protocol for application load screens. Provide a PNG, and that will be displayed while the application actually loads in the background.

Well, PNGs obviously can’t be animated, so we needed another approach. I was not tasked with coming up with the actual animation, and was provided a Flash file by Super Top Secret. Flash was the quickest way to come up with a few animation ideas, but couldn’t be run natively on the device, so we turned to Google’s Swiffy tool to output an HTML5 version. Only one of the brainstormed animations was simple enough to run smoothly in Safari, so the next step was to seamlessly transition from the loading screen to a WebView showing the HTML5 page.

After researching a few existing apps, I tried adding the WebView to the initial application frame, but there was always a delay between the loading PNG being hidden and the page being loaded. So, I added a separate PNG to display while the page loaded in the background. UIWebViewDelegate lets me know when the page has been loaded, so simply implementing webViewDidFinishLoad:(UIWebView *)webView did the trick. When the method is called, hide the transition image so the web view is visible. At that point, the animation plays in the browser. Then, a simple timer hides the web view and loads the app’s main screen after a hardcoded length of time.

So, it goes something like this:

  1. (app is launched by user)
  2. Default.png displays (as usual)
  3. iOS calls application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions on the AppDelegate. Here we create a SplashViewController which both initializes the web view and displays a transitional UIImageView, which is identical to Default.png.
  4. Once the HTML page is loaded, the callback is called. Remove the UIImageView to reveal the UIWebView beneath.
  5. On iOS < 5, there seemed to be a slight delay between when the callback is called and the animation begins. So, we put in [self performSelector:@selector(showWebView) withObject:nil afterDelay:0.5] to delay hiding the image view. Then, another timer is set to hide the web view after three seconds.

The animation ends up being seamless on both iOS4 and 5. Success!

Here’s the code:

SplashViewController.m fragment:

- (void)loadView
{
    appDelegate = (SkiUtahAppDelegate *) [[UIApplication sharedApplication] delegate];
 
    CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
    UIView *view = [[UIView alloc] initWithFrame:appFrame];
    view.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
    self.view = view;
    [view release];
 
    webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, -20, 490, 704)];
    webView.scalesPageToFit = YES;
    webView.delegate = self;
    NSString *htmlPath = [[NSBundle mainBundle] pathForResource:@"startup" ofType:@"html"];
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:htmlPath]];
    [webView loadRequest:urlRequest];
    [self.view addSubview:webView];
 
    splashImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Default"]];
    splashImageView.frame = CGRectMake(0, -20, 320, 480);
    [self.view addSubview:splashImageView];
}
 
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    if([Utils systemVersionLessThan:@"5.0"]) {
        [self performSelector:@selector(showWebView) withObject:nil afterDelay:0.5];
    } else {
        [self performSelector:@selector(showWebView) withObject:nil afterDelay:0.0];
    }
}
 
- (void)showWebView {
    [splashImageView removeFromSuperview];
 
    if([Utils systemVersionLessThan:@"5.0"]) {
        [self performSelector:@selector(continueWithApp) withObject:nil afterDelay:4.5];
    } else {
        [self performSelector:@selector(continueWithApp) withObject:nil afterDelay:3.0];
    }
}
 
- (void)continueWithApp {
    appDelegate.loadedCount ++;
    [appDelegate xmlLoaded];
    [webView removeFromSuperview];
}

AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    splashVC = [[SplashViewController alloc] init];
    [window addSubview:[splashVC view]];
    [window makeKeyAndVisible];
 
    [self doAppInit];
 
    return YES;
}

The only problem with this approach is that the background application loading logic seems to occur before the web view is loaded, so there can be a pretty long delay on the transitional screen before the animation is shown. This is exacerbated in this specific app, as it requires substantial XML data from REST services. Perhaps performing this initialization code in a separate process would help.

Check out the animation and the rest of the free app here.

Comments are closed.