iOS 7 - Restrict Landscape Orientation Only in One View Controller

iOS 7 - Restrict landscape orientation only in one view controller

Fixed it simply by creating UINavigationController class and overriding

-(NSUInteger)supportedInterfaceOrientations
{
AppDelegate *appDelegate = (AppDelegate *) [UIApplication sharedApplication].delegate;
if(appDelegate.isOrientationOn) {
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskPortrait;
}

Use this custom navigation controller class in root window and that's all.

How to disable landscape orientation on a single view at iOS 7/8

Did you put the code above in the ViewController of the view or the NavigationController? You need to put it in the navigation controller, otherwise the navigation controller will rotate, causing the view to rotate as well. Subclass UINavigationController and override shouldAutoRotate:

- (BOOL)shouldAutorotate
{
id currentViewController = self.topViewController;

if ([currentViewController isKindOfClass:[ViewController class]])
return NO;

return YES;
}

Consequently, the navigation controller will only rotate if the displayed view is the view you do not want to rotate.

EDIT

Inside UITabBarController:

- (BOOL)shouldAutorotate
{

if([self.selectedViewController isKindOfClass:[UINavigationController class]]){

UINavigationController *navigationController = (UINavigationController *) self.selectedViewController;
id currentViewController = navigationController.topViewController;

if ([currentViewController isKindOfClass:[ViewController class]])
return NO;
}
}
return YES;
}

How to lock orientation just for one view controller?

This code should work:

    override func supportedInterfaceOrientations() -> Int {
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}

override func shouldAutorotate() -> Bool{
return false
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
return UIInterfaceOrientation.Portrait
}

If it is now working for you, then I suppose your controller is in some another controller(UINavigationController, UITabBarController, UISplitViewController). In this case you need to use this code in that parent controller.

If your navigation controller contain more than one view controller, and you need to disable orientation only for some of them, then you need to inherit UINavigationController class and write there something like:

class NavigationController: UINavigationController {

var shouldRotate: Bool = true

override func supportedInterfaceOrientations() -> Int {
return shouldRotate ? Int(UIInterfaceOrientationMask.Portrait.rawValue) : Int(UIInterfaceOrientationMask.All.rawValue)
}

override func shouldAutorotate() -> Bool{
return shouldRotate
}
}

Then in controller that you need to disable orientation you can disable it for your navigation controller:

class ViewController: UIViewController {

var lastControllerRotationStatus: Bool?

override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)

if let navigationController = self.navigationController as? NavigationController {
lastControllerRotationStatus = navigationController.shouldRotate
navigationController.shouldRotate = false
}
}

override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)

if let navigationController = self.navigationController as? NavigationController {
navigationController.shouldRotate = lastControllerRotationStatus ?? true
}
}
}

But remember, that you need to restore old rotation status after your controller will be pushed out navigation controller. In this example I'm saving rotation status before changing it, and restoring it after controller disappeared. Also you can use some other approach. For example you can overload UINavigationController method popViewController, and there set shouldRotate to false.

The same approach with variable setting from controller you can use for controlling rotation from AppDelegate method application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow) -> Int

Then you do not need to inherit from navigation controller.

Your AppDelegate class code will look like:

class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

var shouldRotate = true
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {

return shouldRotate ? Int(UIInterfaceOrientationMask.All.rawValue) : Int(UIInterfaceOrientationMask.Portrait.rawValue)

}

}

And your controller code will look like:

class ViewController: UIViewController {

var lastControllerRotationStatus: Bool?

override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)

if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate {
lastControllerRotationStatus = appDelegate.shouldRotate
appDelegate.shouldRotate = false
}
}

override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)

if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate {
appDelegate.shouldRotate = lastControllerRotationStatus ?? true
}
}
}

iPhone - allow landscape orientation on just one viewcontroller

You can't support the landscape orientation only for one of the viewcontrollers if you use shouldAutorotateToInterfaceOrientation method of UIViewController.

You have only two choice whether all viewcontrollers support the landscape or no viewcontrollers support it.

If you want to support the landscape only for one, You need to detect device rotation and manually rotate views in the viewcontroller.

You can detect the device rotation by using Notification.

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

Then, you can rotate your views when you detect the device rotation.

- (void)didRotate:(NSNotification *)notification {
UIDeviceOrientation orientation = [[notification object] orientation];

if (orientation == UIDeviceOrientationLandscapeLeft) {
[xxxView setTransform:CGAffineTransformMakeRotation(M_PI / 2.0)];
} else if (orientation == UIDeviceOrientationLandscapeRight) {
[xxxView setTransform:CGAffineTransformMakeRotation(M_PI / -2.0)];
} else if (orientation == UIDeviceOrientationPortraitUpsideDown) {
[xxxView setTransform:CGAffineTransformMakeRotation(M_PI)];
} else if (orientation == UIDeviceOrientationPortrait) {
[xxxView setTransform:CGAffineTransformMakeRotation(0.0)];
}
}

How to lock orientation of one view controller to portrait mode only in Swift

Things can get quite messy when you have a complicated view hierarchy, like having multiple navigation controllers and/or tab view controllers.

This implementation puts it on the individual view controllers to set when they would like to lock orientations, instead of relying on the App Delegate to find them by iterating through subviews.

Swift 3, 4, 5

In AppDelegate:

/// set orientations you want to be allowed in this property by default
var orientationLock = UIInterfaceOrientationMask.all

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return self.orientationLock
}

In some other global struct or helper class, here I created AppUtility:

struct AppUtility {

static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {

if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}

/// OPTIONAL Added method to adjust lock and rotate to the desired orientation
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {

self.lockOrientation(orientation)

UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()
}

}

Then in the desired ViewController you want to lock orientations:

 override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

AppUtility.lockOrientation(.portrait)
// Or to rotate and lock
// AppUtility.lockOrientation(.portrait, andRotateTo: .portrait)

}

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)

// Don't forget to reset when view is being removed
AppUtility.lockOrientation(.all)
}

If iPad or Universal App

Make sure that "Requires full screen" is checked in Target Settings -> General -> Deployment Info. supportedInterfaceOrientationsFor delegate will not get called if that is not checked.
enter image description here

How to lock orientation for iPhone for certain view controllers - Swift?

You need to follow the below steps to lock rotation for specific ViewControllers :-

Step 1: While creating your project, allow all the orientations. Do not select anything in below image.
enter image description here
Step 2: If you want VC1 to have only Portrait Orientation the implementation then add the below two functions in your ViewController Class

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.all //return the value as per the required orientation
}

override var shouldAutorotate: Bool {
return false
}

Step 3: If you wish VC2 to have all the orientation then do not add any code for it.

So the conclusion:-

In project setting, allow all the orientations for whole project. Restriction should be at ViewControllers level not at project level.

If you wish any VC to have all orientation then don't write any code.

If you wish any VC to have specific orientation then implement two functions above.

Only ONE VIEW landscape mode

I am gonna suppose you are targeting iOS 7 here (using XCode 5.1, I think I am right).

First, you have to understand that in order to open even just one view out of over 40 in landscape, your app should allow both landscape and portrait interface orientations.
It is the case by default, but you can check it in your target's settings, General tab, Deployment Info section (see screenshot below).

enter image description here

Then, because you allowed both landscape and portrait for the entire app, you will have to tell every portrait-only UIViewController that it should not autorotate, adding this method's implementation:

- (BOOL)shouldAutorotate {
return NO;
}

Finally, for your specific landscape-only controller, and because you said you are presenting it modally, you can just implement these methods:

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscapeLeft; // or Right of course
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}

Hope this will help,



Related Topics



Leave a reply



Submit