I have a nested view hierarchy for an iPad application that supports orientation changes. It looks similiar to the following.
UIViewController
UIView
- UIView
- UIImageView (disable rotation)
- UIImageView
- UIView (disable rotation)
- UIView
- UIView
...
I would like to lock the orientation for some of my subviews, while allowing others to auto-rotate and resize. I can’t quite seem to figure out how to accomplish this.
One approach seems to be rotating the subviews manually within willAnimateRotationToInterfaceOrientation:. That’s not particularly attractive given the SDK is executing a rotation that I would just be undoing.
Is there a way to simply disable orientation changes for subviews or some other method to restructure my hierarchy?
Autorotation is handled by a view’s UIViewController (
shouldAutorotateToInterfaceOrientation:), so one approach is to arrange your hierarchy such that rotatable views are managed by one view controller, and non-rotatable views by another view controller. Both of these UIViewController’s root views then need adding to the window/superview.The subtlety here is that if you have two view controller’s views on the same level (i.e. added via
addSubview:), only the first view controller (usually the window’srootViewController) will receive theshouldAutorotateToInterfaceOrientation:message.I used this approach myself to achieve a toolbar that rotates, while the main view does not.
Apple’s Technical Q&A QA1688 (“Why won’t my UIViewController rotate with the device?”) talks a little bit about this issue.
Update for iOS 6:
Autorotation now uses
UIViewController‘sshouldAutorotateandsupportedInterfaceOrientationsmethods.shouldAutorotatereturnsYESby default, but remember that a view controller other than therootViewControllerwhose view is a direct subview of the window will NOT receive rotation callbacks anyway.Sample Code for iOS 6:
Create a new project using the “Single View Application” template, and ensure “Use Storyboards” is checked. We’ll use the provided
ViewControllerclass as the rotating view controller (rename it if you like!), and create a secondUIViewControllersubclass calledNonRotatingViewController. Although this view controller will never even receive the rotation callbacks, for completeness and clarity add the following code inNonRotatingViewController.m:In the
MainStoryboardfile, drag out a new view controller object and set its class toNonRotatingViewController, and set its Storyboard ID to “NonRotatingVC”. While you’re there, change the rotating view controller view’s background color to clear (the non rotating view will be added underneath this one), and add a label to each view. InAppDelegate.m, add the following code:This is just instantiating a non rotating view controller and adding its view directly to the window (N.B. at this point the window’s
rootViewControllerhas already been set by the storyboard).Run the project. Rotate the device and marvel at the sight of one label rotating while the other stays still!
Sample Code pre iOS 6:
I did this in a new project – a new View-based Application will do just fine. Add two new view controllers:
RotatingViewControllerandNonRotatingViewController. Inside each of their nibs I just added a label to describe whether the view should rotate or not. Add the following code:‘
RotatingViewController.m‘‘
NonRotatingViewController.m‘‘
AppDelegate.m‘I hope this helps.