Create NIB based auto rotate UIView in IOS

If your application does not support device rotation, its popularity on iTunes Store will be very low. However, how handle all these subview locations depending on screen orientation? Doing this at runtime is a nightmare and it would be very useful to design your two screen orientations in XCODE and save them as a NIB file, and have the program to select one NIB or the other depending on the device orientation. However, just reloading the NIB file at runtime would loose any field value at this time, requiring to save each field state (what a mess). This UIAutoRotateView class will handle that for you, differently.
As I needed to develop more and more IOS application, it stroke me that there was no easy way to make a view rotate and show different subview arrangements easily. I browsed on the Internet and did not find any practical way to do it with few lines of code. The only approach I found that was close enough was using the TAG id of each subview to identify the fields that need to be moved around.
I derived from that concept and added the ADBannerView support to it.
To use the UIAutoRotateView in your program, derive your main view from this one, or use it directly in your NIB file.
Create two NIB files (actually four if you build an application for both iPhone & iPad). The NIB file MUST be named after the View Controller class name, adding "_iPhone" and/or "_iPad" depending on the device and appending "-landscape" to the landscape version.
Ex.: The view controller is named "MyViewController", then the 4 NIB files will be named:
  • "MyViewController_iPhone.nib"
  • "MyViewController_iPhone-landscape.nib"
  • "MyViewController_iPad.nib"
  • "MyViewController_iPad-landscape.nib".
Make sure that your NIB files are attached to your View class or directly to the UIAutoRotateView class. In your NIB files, give each element a TAG number different from 0, making sure to number them the same way. For instance, a TextField containing the user name is tagged 1 in each NIB file, and so on. Don't forget to tag your AdBannerView as well.
Then, build, run and enjoy!!!
Source Code:
//  UIAutoRotateView.h
//  Created by Mogenot Olivier.
//  Copyright (c) 2012 Mogenot Olivier. All rights reserved.
#import <uikit/uikit.h>
@interface UIAutoRotateView : UIView
NSMutableDictionary *portraitViewsFrame, *landscapeViewsFrame;
BOOL                isPortraitMode;
@property (strong, nonatomic) id delegate;

//  UIAutoRotateView.m
//  Created by Mogenot Olivier.
//  Copyright (c) 2012 Mogenot Olivier. All rights reserved.
#import "UIAutoRotateView.h"
#import <iad/iad.h>
@implementation UIAutoRotateView
@synthesize delegate = _delegate;
-(void)awakeFromNib {
if (self) {
if ([super respondsToSelector:@selector(awakeFromNib)]) [super awakeFromNib];
// Initialization code
portraitViewsFrame = [[NSMutableDictionary alloc] init];
isPortraitMode = YES;
for (UIView *obj in [self subviews]) {
if (obj.tag !=0)
[portraitViewsFrame setObject:NSStringFromCGRect(obj.frame) forKey:[NSNumber numberWithInt:obj.tag]];
#pragma mark - Orientation Nib management
-(void)layoutFromDictionary:(NSMutableDictionary*)dict {
// if dictionary is empty, don't do anything
if ([dict count] < 1) return;
for (NSNumber* tag in [dict allKeys]) {
// Lookup for each subview that exists in the dictionary
UIView* vw = [self viewWithTag:[tag integerValue]];
if (vw != nil)
if ([vw isKindOfClass:[ADBannerView class]])    // handle ADBannerView class differently
[((ADBannerView*)vw) setCurrentContentSizeIdentifier:(([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft) || ([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight)) ? ADBannerContentSizeIdentifierLandscape : ADBannerContentSizeIdentifierPortrait];
vw.frame = CGRectFromString([dict objectForKey:tag]);
-(void)readLandscapeLayout {
landscapeViewsFrame = [[NSMutableDictionary alloc] initWithCapacity:[portraitViewsFrame count]];
// Create Nib file name out of controller base name appending device type iPhone or iPad, and -landscape
NSString *nibName = [NSString stringWithFormat:@"%@_%@-landscape",NSStringFromClass([[self delegate] class]),(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) ? @"iPhone" : @"iPad"];
@try {
// Check if the resource file exists
if ([[NSBundle mainBundle] pathForResource:nibName ofType:@"nib"] != nil) {
// Create a shadow controller to load the nib file
UIViewController *ctrl = [[[[self delegate] class] alloc] init];
// load Nib file for the shadow controller
[[NSBundle mainBundle] loadNibNamed:nibName owner:ctrl options:nil];
// Save subview frame dimensions in the landscape dictionary
for (UIView* obj in [[ctrl view] subviews])
if (obj.tag != 0)
[landscapeViewsFrame setObject:NSStringFromCGRect(obj.frame) forKey:[NSNumber numberWithInt:obj.tag]];
// Release the shadow controller
ctrl = nil;
NSLog(@"NIB file %@ not found",nibName);
@catch (NSException *exception) {
NSLog(@"Could not load NIB file %@
%@",nibName, exception.description);
-(void)layoutSubviews {
[super layoutSubviews]; // Call super class function first
// Determine current device orientation
if (!UIInterfaceOrientationIsLandscape([[UIDevice currentDevice] orientation])) {
// If device is not in portrait mode,
// perform subviews layout according to dictionary information
if (!isPortraitMode) {
[self layoutFromDictionary:portraitViewsFrame];
isPortraitMode = YES;
else {
// If landscape dictionary is empty, try to populate it
if (landscapeViewsFrame == nil) [self readLandscapeLayout];
// If dictionnary is populated and device is in protrait mode,
// perform subviews layout according to dictionary information
if (([landscapeViewsFrame count] > 0) && (isPortraitMode)) {
[self layoutFromDictionary:landscapeViewsFrame];
isPortraitMode = NO;

La discussion continue ailleurs

URL de rétrolien :

Fil des commentaires de ce billet