Wednesday, September 8, 2010

iPhone SDK: Switching UIViewControllers on orientation change

I recently started to learn iPhone SDK programming. It is amazingly simple to do and fun to learn.

While trying to program an app that switches UIViewControllers when the phone is rotated, I found the best hint on this blog post. The key is really to use a single view in portrait mode and when the phone is rotated to landscape, present a different UIViewController in modal mode. The tricky part is to remove it again when the phone is rotated back to portrait mode.

For this, the portrait mode has to claim to support all orientations:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

// Return YES for supported orientations

return (interfaceOrientation == UIInterfaceOrientationPortrait ||

interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown ||

interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||

interfaceOrientation == UIInterfaceOrientationLandscapeRight);

}



The mentioned blog post above registers a listener for notifications of the orientation change event emitted by the device. However, I was looking for a different way that uses the methods provided by the UIViewController. Also, I did not want to lose the animation when the phone rotates. It slides in the top bar.

It turns out that the animation that is displayed allows for a callback. This callback is called while the rotation animation is played. In this example the animation callback is used to present the new landscape view.

-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft ||

toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {

self.lView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;

[self presentModalViewController:self.lView animated:YES];

}

}


This example uses the CrossDissolve transition to phase in the landscape view.

Now, since the landscape view is now on top of the portrait view, it will receive the orientation change notification. Using the same trick as above, use the animation callback to dismiss the modal view again.

-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

if (toInterfaceOrientation == UIInterfaceOrientationPortrait ||

toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {

// dismiss this view

[self.parentViewController dismissModalViewControllerAnimated:YES];

}

}


To ensure that the landscape view receives the notification it has to indicate that it supports the new orientation.


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

return YES;

}


The result is an animation that phases in a different view in landscape mode.