So, I've got a project where I need to force an orientation change when a user presses a button. I've created a sample app on github to demonstrate the issue.
@interface DefaultViewController () {
UIInterfaceOrientation _preferredOrientation;
}
Some rotation handling bits
- (BOOL)shouldAutorotate {
return YES;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return _preferredOrientation;
}
And a toggle
- (IBAction)toggleButtonPressed:(id)sender {
_preferredOrientation = UIInterfaceOrientationIsPortrait(_preferredOrientation)
? UIInterfaceOrientationLandscapeRight
: UIInterfaceOrientationPortrait;
[self forceOrientationChange];
}
- (void)forceOrientationChange
{
UIViewController *vc = [[UIViewController alloc] init];
[self presentViewController:vc animated:NO completion:nil];
[UIView animateWithDuration:.3 animations:^{
[vc dismissViewControllerAnimated:NO completion:nil];
} completion:nil];
}
So, this seems to work fine when you just press the toggle button, it changes the orientation as expected. But when I start changing the actual orientation of the device, there is an issue.
Steps to reproduce the issue:
- Open app in portrait orientation
- Press the button to force the orientation change to landscape (Keeping the actual device in portrait)
- Press the button again to force the rotation back to portrait (Still keeping the device in portrait)
- Rotate the actual device to landscape without pressing the button
The result is that the view does not rotate to landscape, but the status bar does.
Any help would be greatly appreciated!
I was able to fix this by adding the following line before presenting and dismissing the view controller:
It's hard to say exactly why this works. This call asks attempts to match the
interfaceOrientation
todeviceOrientation
by callingshouldAutorotateToInterfaceOrientation:
and the subsequent rotation methods ifYES
is returned.It seems the interface and device orientations were getting stuck out of sync due to the workaround required to force an interface orientation in spite of the device orientation. Still shouldn't happen though in my opinion, as the workaround is still a legitimate use of the provided methods. It could be a bug in Apple's rotation/orientation stack.
Complete method:
When we are talking about orientation, they are 2 things that come into the picture:
Device Orientation Interface Orientation As its clear by the name only, Device orientation tells, in which orientation device is, and Interface orientation says in which orientation your app is presenting its interface.
Here what you are doing is, your app is supporting all orientation. You must have check marked all orientations in project.
Now when you are changing orientation of device from portrait to landscape, when you have set interfaceOrientation to be in portrait mode programmatically, this is what happens. As device orientation is changes, orientation of your status bar also changes. But as you have restricted interface of your app to be in portrait orientation, its not changing its orientation..
So this is what you can do:
Use this code: