views:

3792

answers:

2

I'm trying to create an iPhone application that is always in landscape mode, using the Utility application template. Here's what I did:

  • Create a new iPhone application project, using the Utility Application template
  • In Interface Builder, rotate all the views 90 degrees.
  • In Interface Builder, add a label to the middle of the MainView. Stretch it all the way across the view, set the alignment to centered, and set the autosizing springs so that it can stretch horizontally.
  • In Info.plist, add the key "UIInterfaceOrientation" with value "UIInterfaceOrientationLandscapeRight"
  • In the controller classes, change the shouldAutorotateToInterfaceOrientation methods to "return (interfaceOrientation == UIInterfaceOrientationLandscapeRight) || (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);"
  • Run the app.

When I launch my app, it comes up in landscape orientation, but the main view only covers the top half of the display, and it is stretched horizontally. I get the same results in both the simulator and on an actual device. I've seen it with versions 2.2 and 2.2.1 of the SDK.

I have been able to work around the problem by adding the following step to the above:

  • Add "self.view.autoresizesSubviews = NO;" to RootViewController's viewDidLoad method after "[super viewDidLoad];".

If I do this, then it works as expected. But this feels like a hack. Why should this be necessary?

I don't think it is a transformation issue. All elements are drawn in the proper orientation and with the proper scaling. The problem seems to be that the bounds rectangles of the main view gets funky. It looks like the height of the main view is being cut by a little more than half, and the width is being increased by about 50%.

If I do the exact same set of steps using the View-based Application template instead of Utility, then everything works as expected. So I'm pretty sure the problem is specific to how a Utility application manages its views.

Anybody understand what's going on here?

+3  A: 

I was going to say that setting this key does not rotate your interface; you still need to lay out your content in landscape mode and do the appropriate rotation using CFAffineTransform - see "Launching in Landscape Mode" in iPhone OS Programming Guide. Going to find the reference for you, I found this comment: "To launch a view controller–based application in landscape mode in versions of iPhone OS prior to v2.1, you need to apply a 90 degree rotation to the transform of the application’s root view in addition to all the preceding steps. Prior to iPhone OS 2.1, view controllers did not automatically rotate their views based on the value of the UIInterfaceOrientation key. This step is not necessary in iPhone OS 2.1 and later, however."

So if you're running pre-2.1, you need to add this code to your viewDidLoad method in your view controller. (Otherwise, can you post some code?)

-(void)viewDidLoad // After loading the view, transform the view so that the co-ordinates are right for landscape // As described in iPhone Application Programming Guide // Weird, I'm sure this used to be needed, but it doesn't now. The one in CardScrollViewController is needed though. { [super viewDidLoad];

CGAffineTransform transform = self.view.transform;
 CGPoint center = CGPointMake(kScreenHeight / 2.0, kScreenWidth / 2.0);

 // Set the center point of the view to the center point of the window's content area.
 self.view.center = center;

 // Rotate the view 90 degrees around its new center point.
 transform = CGAffineTransformRotate(transform, (M_PI / 2.0));
 self.view.transform = transform;

}

I'm using iPhone OS 2.2.1. I tried the transform you've suggested, but nothing changed. FWIW, I don't think it is the transform, because everything displays in the proper orientation and with proper scaling, but it seems that the bounds rectangle of everything is off.
Kristopher Johnson
+1  A: 

Jane describes the setting of UIInterfaceOrientation to UIInterfaceOrientationLandscapeRight (or UIInterfaceOrientationLandscapeLeft), and the rotation settings recommended in the documentation, but I used a slightly different block of code (to the same end) in my root view controller:

- (void)loadView 
{
    UIView *primaryView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
    primaryView.backgroundColor = [UIColor clearColor];

    // Start in landscape orientation, and stay that way
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    if (orientation == UIInterfaceOrientationLandscapeRight) 
    {
        CGAffineTransform transform = primaryView.transform;

        // Use the status bar frame to determine the center point of the window's content area.
        CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
        CGRect bounds = CGRectMake(0, 0, statusBarFrame.size.height, statusBarFrame.origin.x);
        CGPoint center = CGPointMake(60.0, bounds.size.height / 2.0);

        // Set the center point of the view to the center point of the window's content area.
        primaryView.center = center;

        // Rotate the view 90 degrees around its new center point.
        transform = CGAffineTransformRotate(transform, (M_PI / 2.0));
     primaryView.transform = transform;
    }   

    self.view = primaryView;
    [primaryView release]; 
}

In addition to that, I implemented the following delegate method in my root view controller:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{
    return ( (interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (interfaceOrientation == UIInterfaceOrientationLandscapeRight));
}

Finally, I was encountering weird glitches with the Simulator not auto-rotating properly, so I needed to implement the following delegate method in my UIApplicationDelegate:

- (void)application:(UIApplication *)application willChangeStatusBarOrientation:(UIInterfaceOrientation)newStatusBarOrientation duration:(NSTimeInterval)duration;
{
    // This prevents the view from autorotating to portrait in the simulator
    if ((newStatusBarOrientation == UIInterfaceOrientationPortrait) || (newStatusBarOrientation == UIInterfaceOrientationPortraitUpsideDown))
     [application setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
}

After all that, my application was able to start in landscape (right) and stay in that orientation under the 2.0 firmware and in the Simulator.

Brad Larson