14
votes

I want the splash screen to be displayed each time app becomes active. I have created a function showSplash which I call in applicationDidBecomeActive:

-(void)showSplash
{
    UIImageView *splashScreen = [[UIImageView alloc] initWithImage:[UIImage imageNamed: @"Default.png"]];
    [self.window.rootViewController.view addSubview: splashScreen];
    [self.window makeKeyAndVisible];
    NSLog(@"begin splash");
    [UIView animateWithDuration: 4.2
                          delay: 0.5
                        options: UIViewAnimationOptionCurveEaseOut
                     animations: ^{  
                         splashScreen.alpha = 0.0;
                     }
                     completion: ^ (BOOL finished) {
                         [splashScreen removeFromSuperview];
                         NSLog(@"end splash");
                     }
     ];
}  

This is how I call this function :

- (void)applicationDidBecomeActive:(UIApplication *)application {
[self showSplash];
}

But no splash screen appears. Please correct me.

15
Do you see your log messages being printed? - Phillip Mills
@PhillipMills : Yes. They get printed but the splash is never displayed. - Nitish
@Nitish Maybe you would like to use a launch xib or storyboard. Take a look at useyourloaf.com/blog/2014/12/24/… - dev gr
@devgr : How does that help to display the splash screen whenever app becomes active ? - Nitish
@BlakeMerryman : I am fully aware of this. Thanks though. It's a product I am working on and not an AppStore app. - Nitish

15 Answers

7
votes

If you want the application to have a fresh start every time you get back to it, you could also disable background execution, as stated in the Apple Documentation (last section titled "Opting Out of Background Execution"):

If you do not want your app to run in the background at all, you can explicitly opt out of background by adding the UIApplicationExitsOnSuspend key (with the value YES) to your app’s Info.plist file.

5
votes

after adding the splash view - bring it to front

change

UIImageView *splashScreen = [[UIImageView alloc] initWithImage:[UIImage imageNamed: @"Default.png"]];
[self.window.rootViewController.view addSubview: splashScreen];
[self.window makeKeyAndVisible];

to

UIImageView *splashScreen = [[UIImageView alloc] initWithImage:[UIImage imageNamed: @"Default.png"]];
[self.window addSubview: splashScreen];
[self.window bringSubviewToFront: splashScreen]; //!
[self.window makeKeyAndVisible];
2
votes

Please, ensure your window root view controller main view is the top most view in your App in the moment you want to show splash...

2
votes

Check frame of splashScreen (UIImageView). Set its frame to bounds of your root view controller.

2
votes

You can try to hunt the top view controller with a recursion like this:

- (UIViewController *)findTopViewController {
   return [self topViewControllerFrom:self.window.rootViewController];
}

- (UIViewController *)topViewControllerFrom:(UIViewController *)vc {
    if (vc.navigationController.visibleViewController != nil) {
        return [self topViewControllerFrom:vc.navigationController.visibleViewController];
    }
    if (vc.tabBarController.selectedViewController != nil) {
        return [self topViewControllerFrom:vc.tabBarController.selectedViewController];
    }
    return vc;
}

Now calling [self findTopViewController] should hopefully return the currently visible/top VC of your app, and you can do:

[[self findTopViewController].view addSubview:splashScreen];
...
2
votes

you can do something like:

#import "AppDelegate.h"

#define kSplashScreen (UIScreen.mainScreen.bounds.size.height == 568) ? @"Default-568h" \
            : (UIScreen.mainScreen.bounds.size.height == 667) ? @"Default-667" \
            : (UIScreen.mainScreen.bounds.size.height == 736) ? @"Default-Portrait" \
            : @"Default"

@interface AppDelegate ()
@property (nonatomic) UIWindow *splashWindow;
@property (nonatomic) UIWindow *keyWindow;
@property (nonatomic, getter=isSplashConfigured) BOOL splashConfigured;
@property (nonatomic, getter=isShowingSplash) BOOL showingSplash;
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self animateSplash];
    return YES;
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [self showOrHideSplash];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    [self showOrHideSplash];
}

- (void)showOrHideSplash
{
    [self.splashWindow setHidden:[self isShowingSplash]];
    if ([self isShowingSplash])
    {
        [self.keyWindow makeKeyAndVisible];
    }
    else
    {
        [self.splashWindow makeKeyAndVisible];
        [self animateSplash];
    }
    self.showingSplash = !self.showingSplash;
}


- (void)animateSplash
{
    if ([self isSplashConfigured])
    {
        [self.window.rootViewController.view addSubview:self.splashWindow];
        [self.window makeKeyAndVisible];
    }
    else
    {
        self.keyWindow = [[UIApplication sharedApplication] keyWindow];
        self.splashWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        self.splashWindow.rootViewController = [[UIViewController alloc] init];
        self.splashWindow.rootViewController.view.frame = self.splashWindow.bounds;
        UIImageView *splashImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:kSplashScreen]];
        splashImage.frame = self.splashWindow.bounds;
        [self.splashWindow.rootViewController.view addSubview:splashImage];
        [self.splashWindow makeKeyAndVisible];
        [self.splashWindow setHidden:YES];
        self.splashConfigured = YES;
    }
    NSLog(@"begin splash");
    __weak AppDelegate* weakSelf = self;
    [UIView animateWithDuration:4.2 delay:0.5 options:UIViewAnimationOptionCurveEaseOut animations: ^{
        weakSelf.splashWindow.alpha = 1.0;
        weakSelf.splashWindow.alpha = 0.0;
    } completion: ^(BOOL finished) {
        [weakSelf.splashWindow removeFromSuperview];
        NSLog(@"end splash");
    }];
}
@end
2
votes

This is a bit cumbersome solution, but it works fine. The idea is add new UIWindow on top of all controllers

- (void)showSplash {
    id <UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
    UIWindow *window = [[UIWindow alloc] initWithFrame:[appDelegate window].frame];
    UIViewController *splashController = [UIViewController new];
    UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Default.png"]];
    splashController.view = imgView;
    window.rootViewController = splashController;
    window.windowLevel = UIWindowLevelAlert;
    window.hidden = NO;
    [window makeKeyAndVisible];
    [UIView animateWithDuration:4.2 delay:0.5 options:UIViewAnimationOptionCurveEaseOut animations:^{
        window.alpha = 0.0;
    } completion:^(BOOL finished) {
        window.hidden = YES;
        window.rootViewController = nil;
        [[appDelegate window] makeKeyAndVisible];
        [[appDelegate window] setNeedsDisplay];
    }];
}
2
votes

Please find below a solution for this problem.

Split the splash screen code into two methods; showSplash and hideSplash.

Call showSplash in the method applicationWillResignActive. In the method, create and add the imageView to rootViewController; set it's alpha to 0.0f and then animate it to alpha 1.0f. This is to make sure that the user doesn't see the imageView when the app is going to background.

Now call hideSplash in applicationDidBecomeActive. In hideSplash remove the imageView with animation. See the code below;

-(void)showSplash
{
    _splashScreen = [[UIImageView alloc] initWithImage:[UIImage imageNamed: @"Default"]];
    [self.window.rootViewController.view addSubview:_splashScreen];
    _splashScreen.alpha = 0.0f;
    [UIView animateWithDuration:0.3f animations:^{
        _splashScreen.alpha = 1.0f;
    }];
}
- (void)hideSplash
{
    [UIView animateWithDuration: 4.2
                          delay: 0.5
                        options: UIViewAnimationOptionCurveEaseOut
                     animations: ^{
                         _splashScreen.alpha = 0.0;
                     }
                     completion: ^ (BOOL finished) {
                         [_splashScreen removeFromSuperview];
                         NSLog(@"end splash");
                     }
     ];
}
- (void)applicationWillResignActive:(UIApplication *)application {
    [self showSplash];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
    [self hideSplash];
}

I hope this helps! :-)

2
votes

Add

splashScreen.frame = self.window.rootViewController.view.frame;

below

UIImageView *splashScreen = [[UIImageView alloc] initWithImage:[UIImage imageNamed: @"alertBg.png"]];

example

-(void)showSplash
{
    UIImageView *splashScreen = [[UIImageView alloc] initWithImage:[UIImage imageNamed: @"Default.png"]];
    splashScreen.frame = self.window.rootViewController.view.frame;
    [self.window.rootViewController.view addSubview: splashScreen];
    [self.window makeKeyAndVisible];
    NSLog(@"begin splash");
    [UIView animateWithDuration: 4.2
                          delay: 0.5
                        options: UIViewAnimationOptionCurveEaseOut
                     animations: ^{
                         splashScreen.alpha = 0.0;
                     }
                     completion: ^ (BOOL finished) {
                         [splashScreen removeFromSuperview];
                         NSLog(@"end splash");
                     }
     ];
}
2
votes

The best way to achieve this is to add the image in AppDelegate's window. In the below code statusView is one of the view, which consist of some image. So add it to your AppDelegate's window as a subView

[[[[UIApplication sharedApplication] delegate] window] addSubview:statusView];

Now whenever you want it to appear for some amount of time, you show this view, but same time bring it to front.

-(void)showStatusView{

    [UIView animateWithDuration:0.5 animations:^{
        [[[[UIApplication sharedApplication] delegate] window] bringSubviewToFront:statusView];
        statusView.alpha = 1;
    }];
}

Better Call the above method on the AppDelegate's method didBecomeActive.

Also, show the splash screen as soon as application is going to resign active. This way, iOS will take the snapshot of the screen, which will be shown for fraction of seconds when the app is about to become active.

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [self showStatusView];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    [self showStatusView];
}

Once the app is active, you can show the actual splash screen for some duration & then your usual app state.

2
votes

First create your launch screen or image in didFinishLaunchingWithOptions function.

AppDelegate.m

After this write your code like this-

enter image description here

2
votes

Root view controller is not always the presented view controller. This can cause your splash screen to be hidden under bunch of other view controllers. Try using something like (swift syntex):

func getTopViewController() -> UIViewController?{
    if var topController = UIApplication.sharedApplication().keyWindow?.rootViewController{
        while ((topController.presentedViewController) != nil) {
            topController = topController.presentedViewController!
        }
        return topController
    }
    return nil
}

And add your splash view to the top view controller

1
votes

launch your application normally every-time, call your method in applicationBecomeActive, and add you image view on Appdelegate.window and remove it after some time by timer.

[self.window addSubview: splashScreen];
0
votes

You should use the following line:

[self.window addSubview: splashScreen];

instead of

[self.window.rootViewController.view addSubview: splashScreen];
0
votes

You can reuse your launchScreen to show up instead of showing imageview. This comes handdy when you have complex launchscreen instead of single image as a splash screen.

func applicationWillResignActive(_ application: UIApplication) {
        guard let window = UIApplication.shared.windows.last,
              let launchScreen = UIStoryboard(name: "LaunchScreen", bundle: nil).instantiateInitialViewController(),
              let launchView = launchScreen.view else {return}
        launchView.tag = 8888
        launchView.frame = window.bounds
        launchView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        window.addSubview(launchView)
        window.makeKeyAndVisible()
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        guard let window = UIApplication.shared.windows.last,
              let view = window.viewWithTag(8888) else {return}
        view.removeFromSuperview()
    }