0

I'm implementing a photo/video picking interface similar to Apple's Camera app. I need to do manual interface rotation since I don't want the preview view to rotate, but I do want to rotate the controls accordingly. Therefore I have the following code in my view controller (which is the root view controller of the app):

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

To detect orientation changes I registered my VC for the according notifications in viewDidLoad:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(deviceOrientationDidChange)
                                             name:UIDeviceOrientationDidChangeNotification
                                           object:[UIDevice currentDevice]];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

This works as expected except when I start the app in an orientation other then portrait. My callback gets called; however, the current device orientation is always UIDeviceOrientationPortrait, even when I hold my device sideways when starting the app. The same holds for the status bar orientation.

How can I figure out the device orientation right after app start? I know it's possible because Apple is doing it in their Camera app. The question is, is there any official way, or do they use some magic internal APIs?

Update

Anna's answer turns out to be correct, but you should also read the comments. TL;DR: The effect occurs on iPhone 6 (Plus) when the app is not optimized for them.

Frank Rupprecht
  • 9,191
  • 31
  • 56
  • for this answer check this post. http://stackoverflow.com/questions/5888016/ios-device-orientation-on-load/32758397#32758397 – jenish Sep 24 '15 at 10:00

1 Answers1

1

First of all, you don't want to look at the UIDevice orientation (see this post).

I think you're getting a spurious result before the UI is done configuring itself. In other words, it reports Portrait because it's just not ready at that point in the startup process. Why is it sending notifications at all? Not sure; but, you definitely don't want to use them for your task.

I don't quite understand what you're using the initial orientation for, but I have an alternate way to solve your problem: you can keep a view static by counter-rotating it. When your view controller receives a rotation message (I.e. viewDidRotate, pre-iOS 8), you change the transform on your static view to rotate in the direction opposite that rotation.

There are probably some clever ways to do it with autolayout as well, but I haven't figured them out yet... :-p

EDIT:

Some code...

YMMV -- this works, but I haven't touched it in a while! You might have to play with it a little... and contrary to what I said in the comments, it looks like I am animating the rotation. But, it really doesn't move! I think the counter-rotation animation gets cancelled out by the system's rotation of the whole display... or something.

simViewControllerContainer is the view I'm preventing from rotating.

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Set simView container's orientation if the device started in landscape
    if ( self.interfaceOrientation == UIInterfaceOrientationLandscapeRight ) {
        simViewControllerContainer.center = (CGPoint) {self.view.bounds.size.height/2, self.view.bounds.size.width/2};
        simViewControllerContainer.transform = CGAffineTransformMakeRotation(-M_PI/2);
    }
    else if ( self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft ) {
        simViewControllerContainer.center = (CGPoint) {self.view.bounds.size.height/2, self.view.bounds.size.width/2};
        simViewControllerContainer.transform = CGAffineTransformMakeRotation(M_PI/2);
    }
}

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

    BOOL doubleRotation =
    (UIInterfaceOrientationIsPortrait(self.interfaceOrientation) && UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) ||
    (UIInterfaceOrientationIsLandscape(self.interfaceOrientation) && UIInterfaceOrientationIsLandscape(toInterfaceOrientation));

    if ( toInterfaceOrientation == UIInterfaceOrientationLandscapeRight ) {
        [UIView animateWithDuration:duration animations:^{
            if ( !doubleRotation ) {
                // For a double-rotation, we don't want to change the center -- it's the same:
                // a double-rotation is landscape to landscape or portrait to portrait -- same center.
                simViewControllerContainer.center = (CGPoint) {self.view.bounds.size.height/2, self.view.bounds.size.width/2};
            }
            simViewControllerContainer.transform = CGAffineTransformMakeRotation(-M_PI/2);
        }];
    }
    else if ( toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft ) {
        [UIView animateWithDuration:duration animations:^{
            if ( !doubleRotation ) {
                simViewControllerContainer.center = (CGPoint) {self.view.bounds.size.height/2, self.view.bounds.size.width/2};
            }
            simViewControllerContainer.transform = CGAffineTransformMakeRotation(M_PI/2);
        }];

    }
    else if ( toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown ) {
        [UIView animateWithDuration:duration animations:^{
            if ( !doubleRotation ) {
                simViewControllerContainer.center = (CGPoint) {self.view.bounds.size.height/2, self.view.bounds.size.width/2};
            }
            simViewControllerContainer.transform = CGAffineTransformIdentity;
        }];

    }
    else if ( [UIDevice currentDevice].orientation == UIDeviceOrientationPortrait ) {
        [UIView animateWithDuration:duration animations:^{
            if ( !doubleRotation ) {
                simViewControllerContainer.center = (CGPoint) {self.view.bounds.size.height/2, self.view.bounds.size.width/2};
            }
            simViewControllerContainer.transform = CGAffineTransformIdentity;
        }];
    }
}
Community
  • 1
  • 1
Anna Dickinson
  • 3,307
  • 24
  • 43
  • Thanks for your help, Anna. My goal was to imitate the behavior of Apples Camera app, which doesn't rotate it's window. Normally you can see the screen rectangle rotate when an app interface rotates. However, the Camera app doesn't do that, it only rotates the controls. And that makes sense, because the camera feed, that is displayed in the background, rotates with the camera anyways. I'd have to counter-act that if I would rotate my background view. – Frank Rupprecht Nov 13 '14 at 20:03
  • Mainly I need the orientation to set the transformation of the `AVAssetWriter` I use for video recording correctly. If you don't tell it the orientation of the incoming video samples it saves the video in the default orientation. So videos taken in portrait end up rotated when watching the recorded video. – Frank Rupprecht Nov 13 '14 at 20:05
  • When you counter-rotate a view by setting the transform, it doesn't actually move -- it doesn't animate. iOS knows not to move it because the transform "matches" the one it was intending to perform. – Anna Dickinson Nov 13 '14 at 20:15
  • Can you set a transform on the video? Maybe it would do something similar. – Anna Dickinson Nov 13 '14 at 20:16
  • This is tedious, but it seems to be the only way. Do you have some sample code on how to set the view's transform to exactly counter-act the rotation? That would be really helpful. And thanks again for your help! – Frank Rupprecht Nov 13 '14 at 20:42
  • By the way, the device orientation and the status bar orientation stay in portrait unless I rotate the device—no matter how long after the app start I query them. – Frank Rupprecht Nov 13 '14 at 20:44
  • Anna, I tested your approach: when rotating, I set the view transform to rotate in the opposite direction at the same time—and it works. However, I still see the typical animation of the window frame I was trying to get rid of... – Frank Rupprecht Nov 17 '14 at 14:00
  • Anna, you were right all the time! It was my "fault", and here is why: I was testing on an iPhone 6 Plus. But I did not yet optimize my app for the new screen sizes (I did not provide the launch images), which means the app runs in this scaled-up emulated fashion on these devices. This must cause the rotation animation artifacts. On smaller iPhones it all works as you described. Thanks again for your help! – Frank Rupprecht Nov 17 '14 at 19:38