1

My goal is changing lock/unlock orientation using button. In lock mode, orientation can be switched by button, and in unlock mode, orientation is determined by sensor.
I tried to achieve this with [[UIDevice currentDevice] setValue:[NSNumber numberWithInt:orientation] forKey:@"orientation"], but this code has problem.
Assume that currently my app is 'Lock mode, portrait UI, portrait device'. Then I rotate device to landscape left, and unlock orientation. I expected [[UIDevice currentDevice] orientation] should be UIDeviceOrientationLandscapeLeft. But the value was UIDeviceOrientationPortrait though the real device is in landscape!

I tried also notification center with code below.

[[NSNotificationCenter defaultCenter]  
           addObserver:self  
              selector:@selector(onDeviceOrientationChanged:)  
                  name:UIDeviceOrientationDidChangeNotification  
                object:nil];

But this code does not working properly. If the device is in landscape and UI orientation is set to portrait by [[UIDevice currentDevice] setValue:[NSNumber numberWithInt:UIDeviceOrientationPortrait], onDeviceOrientationChanged is not called when I rotate device to portrait. I think device's orientation value is already set to portrait (by my code, not sensor).

ps. Of course, I checked Required full screen option.

EDIT: It would be also good answer to know how to get device's real orientation which is not affected by [[UIDevice currentDevice] setValue].

khcpietro
  • 1,459
  • 2
  • 23
  • 42

1 Answers1

4

I solved this problem using MotionManager. When I lock (or change) orientation, [[UIDevice currentDevice] setValue:[NSNumber numberWithInt:orientation] forKey:@"orientation"] enough as usual.
However, when I unlock orientation, I refreshed orientation using MotionManager with below code.

CMMotionManager motionManager = [[CMMotionManager alloc] init];

[motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue]
    withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) {
        [motionManager stopAccelerometerUpdates];

        CMAcceleration acceleration = accelerometerData.acceleration;
        UIInterfaceOrientation orientation;
        if (acceleration.x >= 0.75) {
            orientation = UIInterfaceOrientationLandscapeLeft;
        } else if (acceleration.x <= -0.75) {
            orientation = UIInterfaceOrientationLandscapeRight;
        } else if (acceleration.y <= -0.75) {
            orientation = UIInterfaceOrientationPortrait;
        } else if (acceleration.y >= 0.75) {
            orientation = UIInterfaceOrientationPortraitUpsideDown;
        } else {
            return;
        }
        [[UIDevice currentDevice] setValue:[NSNumber numberWithInt:orientation]
                            forKey:@"orientation"];
        [UINavigationController attemptRotationToDeviceOrientation];
    }];

Of course, you should aware of supportedInterfaceOrientations and shouldAutorotate methods.

khcpietro
  • 1,459
  • 2
  • 23
  • 42