2 ways to rotate
I spent too long writing a few lines of code that I no longer need. I feel that I need to do something with them so here they are.
Below are 2 methods for rotating a view while keep the rest of the UI from rotating (or at least appearing rotated). Since iOS 4, UINavigationController and friends are more easygoing about handling this automatically. Both of these methods really only apply to the situation where you are managing a custom view hierarchy and not relying on UINavigationController and UITabBarController like a good iPhone citizen. (You will notice in both methods I have mysterious object called “customContainerController” which is managing my view hierarchy, if you are so inclined you can try it out here)
Method 1: Brute Force
If you need to allow the rotation of a single view but don’t actually want to rotate the entire interface of the app, the following will allow you to do that. It isn’t really complex, but the devil is in the details. You need to bump and nudge a lot of things and you can spend a lot of time building and tweaking.
Interesting things:
You must set the bounds after applying the transform.
The bounds is manipulated as if the origin is in the upper left hand corner (UIInterfaceOrientationPortrait).
You need to adjust the bounds +20 / -20 to account for moving the status bar around.
Changing the orientation of the status bar does not change the interface orientation of the device.
You need to rotate the status bar back when dismissing the view (do that with no animation).
If you need the keyboard this won’t work because the keyboard respects the current interface orientation.
- (IBAction)close:(id)sender {
UIApplication *application = [UIApplication sharedApplication];
[application setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
[self.customContainerController loadThatOtherViewController];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
//manually rotate
//bounds changes are made as if the phone never rotated
//we are making these bounds tweaks to move aorund the status bar
CGRect bounds = [self.customContainerController.view bounds];
CGFloat r = 0;
switch ( interfaceOrientation ) {
case UIInterfaceOrientationPortrait:
r = 0;
break;
case UIInterfaceOrientationLandscapeRight:
r = M_PI/2;
bounds.origin.y-=20;
bounds.size.height+=20;
bounds.size.width-=20;
break;
case UIInterfaceOrientationPortraitUpsideDown:
r = M_PI;
bounds.origin.y-=20;
break;
case UIInterfaceOrientationLandscapeLeft:
r = 3*M_PI/2;
bounds.origin.x+=20;
bounds.origin.y-=20;
bounds.size.height+=20;
bounds.size.width-=20;
break;
}
UIApplication *application = [UIApplication sharedApplication];
[UIView animateWithDuration:[application statusBarOrientationAnimationDuration]
animations:^(void) {
CGAffineTransform t;
t = CGAffineTransformIdentity;
t = CGAffineTransformRotate(t, r);
self.view.transform = t;
self.view.frame = bounds;
}];
[application setStatusBarOrientation:interfaceOrientation animated:YES];
return YES;
}
Method 2: Tricking UIKit
This time we need to make UIKit ask us about rotation at an opportune time. To do this we can create and destroy a UIVIewController, causing all of the View Controller machinery to kick in. I picked this idea up from: SO
Interesting things:
Unlike the 1st method, you get to hook into the normal view controller autoresizing.
Presenting/dismissing a blank VC without animation is not visible to the user.
- (IBAction)close:(id)sender {
self.isClosingDown = YES;
//doing this to force an autorotation
UIViewController *c = [[UIViewController alloc]init];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
[c release];
[self.customContainerController loadThatOtherViewController];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(self.isClosingDown)
return (UIInterfaceOrientationPortrait == interfaceOrientation);
return YES;
}