Open doors effect at App launch

This is a copy of a blog entry I originally wrote for ios-blog

There are a number of apps in the App Store that launch with a set of closed doors, these are then opened to present the actual UI underneath it.

I had to create this effect for an app I wrote for a client

I’d assumed when I started that this would be a relatively simple task, just take the initial default image, cut it in half and a simple bit of animation would move them out of the way. What I hadn’t counted on is getting the orientation of the device from launch is not straightforward. The trick is to remember that the first view that is loaded will always assume it’s in Portrait mode, the view is then informed via the willRotate method that in fact the orientation is different and you can then handle this appropriately. The second trick is knowing that the willRotate takes a little bit of time to fire, so it’s now a simple case of delaying the call to the method that handles the animation.

The viewWillAppear method loads the images assuming that the view is in portrait and sets up a timer to call the openDoors method

-(void)viewWillAppear:(BOOL)animated {
    //All apps start in portrait mode, with the home button at the bottom,
    //If the device is being held with the home button in any other location then a
    //willRotate is fired!
    isPortrait = YES;
    doorsClosed = YES;

    //We assume we are in portrait mode until told otherwise
    self.leftDoor.image = [UIImage imageNamed:@"DoorLeftiPadPortrait.png"];
    self.rightDoor.image = [UIImage imageNamed:@"DoorRightiPadPortrait.png"];
    self.backgroundSplash.image = [UIImage imageNamed:@"SlideBackgroundiPadPortrait.png"];

    //Add a delay to the open doors sequence, this allows the OS to determine
    //the correct orientaion and fire the all important willRotate

    [NSTimer scheduledTimerWithTimeInterval: 3.5
                                     target: self
                                   selector: @selector(openDoors)
                                   userInfo: nil
                                    repeats: NO];

The willRotate method then ensures that the correct image is loaded

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return YES;

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    isPortrait = UIDeviceOrientationIsPortrait(toInterfaceOrientation);
    if (!isPortrait) {
        //If the doors haven't already been opened then change them to the landscape ones
        if (doorsClosed) {
            self.leftDoor.image = [UIImage imageNamed:@"DoorLeftiPadLandscape.png"];
            self.rightDoor.image = [UIImage imageNamed:@"DoorRightiPadLandscape.png"];
        self.backgroundSplash.image = [UIImage imageNamed:@"SlideBackgroundiPadLandscape.png"];
    } else {
        self.backgroundSplash.image = [UIImage imageNamed:@"SlideBackgroundiPadPortrait.png"];

The openDoors method then just works out how far to move the images and kicks of the animation, I’ve included the old UIView beginAnimation and the Blocks way

-(void)openDoors {
    //Determine how far the doors need to move for them to disappear from view
    float adjust = (CGRectGetWidth(self.view.frame) > CGRectGetHeight(self.view.frame)) ? CGRectGetWidth(self.view.frame) : CGRectGetHeight(self.view.frame);
    //Retrieve the original frame and then adjust the X position accordingly
    CGRect leftFrame = self.leftDoor.frame;
    CGRect rightFrame = self.rightDoor.frame;;

    leftFrame.origin.x = -adjust;
    rightFrame.origin.x += adjust;

//Old School Animation

//Set up the animation, change the frames and commit it
//	[UIView beginAnimations:@"swipe" context:nil];
//	[UIView setAnimationDuration:1.2];
//	[UIView setAnimationDelay:0.0];
//	[UIView setAnimationDelegate:self];
//      self.leftDoor.frame = leftFrame;
//	self.rightDoor.frame = rightFrame;
//	[UIView commitAnimations];

    [UIView animateWithDuration:1.2
                        self.leftDoor.frame = leftFrame;
                        self.rightDoor.frame = rightFrame;

    doorsClosed = NO;

Note this effect only works if the app is launching for the first time, i.e. not from the background.

I’ve put together a sample project that puts this all into practice

Hope you find this useful, or if you have a better way of creating the same effect please let me know

See what I do