Mark
Mark

Reputation: 18204

What's the proper way to detect interface orientation at launch?

[Question updated]

So here is the problem, I finally narrowed it down to this. If you create a new UIViewController in all methods

- (id)init;
- (void)loadView;
- (void)viewDidAppear:(BOOL)animated;
- (void)viewDidLoad;
(...)

The standard interfaceOrientation is Portrait and if landscape mode is detected it will quickly rotate to that orientation. Which can then be detected using the:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation;

The problem is that on the iPad, it's quiet difficult to prepare your interface for the current interface orientation within the loadView (or one of the others) as it will only return Portrait. This will cause for a few problems:

1) I want my content to reload in portait mode, but NOT in landscape mode. Normally I would place an if statement in the loadView. If in portrait mode, reload content. But in this case it will always return portrait and thus always loads content.

2) I want to use 'presentPopoverFromRect:inView:permittedArrowDirections:animated:'-method when in portrait mode so it will present the popover menu automaticly when the application starts. This will crash the application when launched in portrait mode. Reason: 'Popovers cannot be presented from a view which does not have a window.'.

The only safe assumption is within 'didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation', but this method will not be fired if it launches in portrait mode.

//----

Update (15.37)

'UIApplicationWillChangeStatusBarOrientationNotification'

Will only be posted when the user swaps from portrait to landscape (or vica versa). If interface was the problem then this can easily be solved with observing for that notification and

if (UIDeviceOrientationIsPortrait(interfaceOrientation)) {
    // layout subviews for portrait mode
} else {
    // layout subviews for landscape mode
}

But the problem is that I want to know in which mode it is at launch to determine rather or not I should reload the content, I can't reload the content and when it swaps to landscape cancel it.

Upvotes: 7

Views: 9222

Answers (3)

Mark
Mark

Reputation: 18204

I am not sure if this will actually solve my problem but looking at the documentation I found the following:

typedef enum {
   UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
   UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
   UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,
   UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
} UIInterfaceOrientation;

and

typedef enum {
   UIDeviceOrientationUnknown,
   UIDeviceOrientationPortrait,
   UIDeviceOrientationPortraitUpsideDown,
   UIDeviceOrientationLandscapeLeft,
   UIDeviceOrientationLandscapeRight,
   UIDeviceOrientationFaceUp,
   UIDeviceOrientationFaceDown
} UIDeviceOrientation;

So since FaceUp and FaceDown have been added looking at the orientation of the Device is pointless for Interface reasons. Therefor, theoretically, @MarkAdams is right mentioning that in this case [[UIApplication sharedApplication] statusBarOrientation] should be used for the interface orientation.

Or of course the UIViewController has the option 'interfaceOrientation'.

Upvotes: 1

Pascal
Pascal

Reputation: 16941

The proper way is to ask the device for its orientation as a view technically has no orientation. ;)

So you're correct in using UIDevice. From the documentation you can see that you first need to generate device orientation notifications before this information is correct. Then it will work as desired.

UIDevice *myDevice = [UIDevice currentDevice];
[myDevice beginGeneratingDeviceOrientationNotifications];
UIDeviceOrientation currentOrientation = [myDevice orientation];
[myDevice endGeneratingDeviceOrientationNotifications];

Note: This gives you the current orientation of the device. If the currently visible/top view controller did not allow rotation to this orientation, you will nevertheless get the current device orientation, not the one the topmost view controller currently uses.


Edit after question was updated:

You are correct that the orientation for the topmost view controller (worked correctly for subview controllers) always returns 1 (i.e. UIInterfaceOrientationPortrait) in loadView. However the method willRotateToInterfaceOrientation:duration: will immediately afterwards be called, and the orientation passed there is correct, so you should be able to use that method.

- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toIfaceOrient
                                 duration:(NSTimeInterval)duration

Upvotes: 6

Mark Adams
Mark Adams

Reputation: 30846

Try [[UIApplication sharedApplication] statusBarOrientation].

Upvotes: 8

Related Questions