I want some of my ViewControllers landscape and some portrait so this is what I did:
I enabled landscape mode:
Next I added these lines of code to the view controllers I wanted to be Portrait:
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationPortrait;
}
-(BOOL)shouldAutorotate
{
return NO;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationPortrait;
}
However when I rotate them they still go to landscape mode.How can I fix that?
Here is how I do it.
Make a UINavigationController parent class.
inside you UINavigationController (parent) override these methods like:
- (NSUInteger)supportedInterfaceOrientations
{
if([self.topViewController respondsToSelector:@selector(supportedInterfaceOrientationsForThisContorller)])
{
return(NSInteger)[self.topViewController performSelector:@selector(supportedInterfaceOrientationsForThisContorller) withObject:nil];
}
return UIInterfaceOrientationPortrait;
}
- (BOOL)shouldAutorotate
{
if([self.visibleViewController respondsToSelector:@selector(shouldAutorotateNow)])
{
BOOL autoRotate = (BOOL)[self.visibleViewController
performSelector:@selector(shouldAutorotateNow)
withObject:nil];
return autoRotate;
}
return NO;
}
Now your NavigationController should be a subclass of the UINavigationContorller parent
Swift 3:
Inside your UINavigationController subclass do this
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
get {
return self.topViewController?.supportedInterfaceOrientations ?? .all
}
}
override var shouldAutorotate: Bool {
return self.topViewController?.shouldAutorotate ?? false
}
Update Taken from Matt's answer if you don't want to subclass:
first: make your viewController a delegate of the navigationController in viewDidLoad
self.navigationController?.delegate = self
Then declare UIViewController extension to respond to the delegate method as shown below:
extension UIViewController: UINavigationControllerDelegate {
public func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask {
return navigationController.topViewController?.supportedInterfaceOrientations
}
}
The Apple designed way to do this for UINavigationController
is via UINavigationControllerDelegate
.
Usually I just update this delegate to do the following and delegate it to the top displaying controller in the navigation controller's stack:
#pragma mark - UINavigationControllerDelegate
- (NSUInteger)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController
{
return [navigationController.topViewController supportedInterfaceOrientations];
}
In my opinion the UINavigationController
should just default to the above behavior but this is the api Apple has provided :)
As for the info plist file I uncheck all of the options and handle it all in code as it has caused issues for me in the past and I got tired of dealing with it.
For simplicity, for iPad, if Supported interface orientations (iPad) property in info.plist includes all the four orientations, with UIRequiresFullScreen property value as NO, iOS will treat your app as supporting split view. If an app supports split view feature, you can not disable it from rotating, at least by the ways above.
Let's go deep into details.
First, we need to know which factors will influence the screen orientation:
1. Project settings(info.plist)
There are two places we can do this setting:
Project->Target->General->Device Orientation
info.plist of the project
The two methods are the same and one will automatically sync the other setting. In info.plist file, Supported interface orientations (iPad) property is for iPad setting (choose iPad for Device section), and Supported interface orientations property is for iPhone and Univeral (choose iPhone or Universal for Device section, and these two settings will always be the same.).
2. Set supported screen orientations programmatically
There are two ways to configure the supported orientations while coding:
supportedInterfaceOrientationsForWindow:
method in UIApplicationDelegate
supportedInterfaceOrientations
method in UIViewController
The iOS system will check the common orientations defined in the two methods and use the common orientations as the supported orientations for the view controller.
3. Set shouldAutorotate
property in UIViewController
This is a read-only property and used for control if the view controller is rotatable or not. You can override the property in your view controller, or even change the property to read-write property, so that you can modify the property while your app is running. For example:
override public var shouldAutorotate: Bool {
get {
return self.shouldAutorotateVariable
}
set {
self.shouldAutorotateVariable = newValue
}
}
shouldAutorotateVariable
is a private property in your view controller.
If a view controller's shouldAutorotate
property is set to false
, iOS will omit the following settings:
supportedInterfaceOrientationsForWindow:
method in UIApplicationDelegate
supportedInterfaceOrientations
method in UIViewController
iOS will only use Project settings (info.plist).
If the shouldAutorotate
property is not overriden or is set to true
, then iOS will use the common orientations defined in the following two methods:
supportedInterfaceOrientationsForWindow:
method in UIApplicationDelegate
supportedInterfaceOrientations
method in UIViewController
If the above two methods are not supplied, iOS will use the Project settings (info.plist).
From iOS9, iPad supports split view feature. Refer to Slide Over and Split View Quick Start for the setting of split view.
For simplicity, if Supported interface orientations (iPad) property in info.plist includes all the four orientations, with UIRequiresFullScreen property value as NO, iOS will treat your app as supporting split view. If the app supports split view, the following two settings will be omitted:
supportedInterfaceOrientationsForWindow:
method in UIApplicationDelegate
supportedInterfaceOrientations
method in UIViewController
The shouldAutorotate
property in UIViewController
will also be omitted.
That is to say, if an app supports split view feature, you can not disable it from rotating, at least by the ways above.
If Supported interface orientations (iPad) property in info.plist value doesn't include all four orientations, or UIRequiresFullScreen property is set to YES, the app will not support split view, and the screen orientation control logic is the same with iPhone above.
Note: for the Project settings (info.plist), it's better to set the following three properties directly inside info.plist:
- Supported interface orientations (iPad)
- Supported interface orientations
- UIRequiresFullScreen
It is confusing if you try to set through Project->Target->General->Device Orientation: even Device is set as Universe, the setting in iPad will still take effect.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With