-3

I have a UITabBarController controlling multiple UIViewControllers

which display different UIViews.

ALL BUT ONE of the views should display ONLY IN PORTRAIT MODE, without being able to rotate, while ONLY ONE VIEW should display in LANDSCAPE MODE ONLY, without being able to rotate.

It seems trivial, but I am unable to achieve this... Either all views are in portrait mode or all of them are in landscape mode. They either all rotate or none of them does.

Below is the code for the Landscape view, but the instructions are completely neglected by the compiler and the view rotates to portrait mode when the device is rotated.

-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation  
{
     return UIInterfaceOrientationLandscapeRight;  
}

-(BOOL) shouldAutorotate 
{
     return NO; 
}

The only way to stop the autorotation is by ticking a box in Device Orientation in IB, but then the setting is applied to ALL the views and none of them rotates..

I've read that recently it is no longer possible to apply individual settings to each view, which seems to be absurd.

Is there any workaround?

Edited with more info: @ManWithBeard, I cannot figure out how to adapt your code to mine.. My UITabBarController controls different UIViewControllers, defined in their headers as follows:

@interface Portrait_ViewController : UIViewController
@interface LandscapeViewController : UIViewController

The AppDelegate takes to the first view controller with

[self.tabBarController setSelectedViewController: Portrait_ViewController]

and then from any ViewContoller, I move to the desired one with

[self.tabBarController setSelectedIndex:index]

I don’t understand how to apply UITabBarController to the UIViewControllers with @interface ChildOrientationTabBarController : UITabBarController as you have suggested.

jeddi
  • 651
  • 1
  • 12
  • 21

2 Answers2

0

Application asks only top controller for interface orientation.

In your case UITabBarController is top controller and other controllers are children of it.

You need create own subclass of UITabBarController override this methods and pass values from current selected controller instead.

Example of such containers:
Swift

class ChildOrientationTabBarController: UITabBarController {
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return selectedViewController?.supportedInterfaceOrientations ?? .portrait
    }
    override var shouldAutorotate: Bool {
        return selectedViewController?.shouldAutorotate ?? false
    }
}
class ChildOrientationNavigationController: UINavigationController {
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return topViewController?.supportedInterfaceOrientations ?? .portrait
    }
    override var shouldAutorotate: Bool {
        return topViewController?.shouldAutorotate ?? false
    }
}

Objective-C

@interface ChildOrientationTabBarController : UITabBarController
@end
@implementation ChildOrientationTabBarController

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return [self.selectedViewController supportedInterfaceOrientations] ?: UIInterfaceOrientationMaskPortrait;
}

- (BOOL)shouldAutorotate {
    return [self.selectedViewController shouldAutorotate] ?: NO;
}
@end

@interface ChildOrientationNavigationController : UINavigationController
@end
@implementation ChildOrientationNavigationController

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return [self.topViewController supportedInterfaceOrientations] ?: UIInterfaceOrientationMaskPortrait;
}

- (BOOL)shouldAutorotate {
    return [self.topViewController shouldAutorotate] ?: NO;
}
@end

And AppDelegate should override supportedInterfaceOrientation method as:
Swift

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return window?.rootViewController.supportedInterfaceOrientations ?? .portrait
}

Objective-C

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
    return [[window rootViewController] supportedInterfaceOrientations] ?: UIInterfaceOrientationMaskPortrait;
}
ManWithBear
  • 2,787
  • 15
  • 27
  • Sorry I am not familiar with Swift. Could you please post the objective c code? – jeddi Mar 28 '19 at 15:20
  • @jeddi I not sure I remember how to do it :D I will give it a try – ManWithBear Mar 28 '19 at 15:21
  • @jeddi added. Feel free to report back any syntax errors. I tried my best :) – ManWithBear Mar 28 '19 at 15:27
  • Very kind of you to post the code in objective c. I don't understand however this: if in the AppDelegate I put "supportedInterfaceOrientations] ?: UIInterfaceOrientationMaskPortrait;" wouldn't this limit the whole app to Portrait mode? – jeddi Mar 28 '19 at 16:14
  • @jeddi no, it will try to get supported interface orientation from `rootViewController` (I assume it will be `ChildOrientationTabBarController`) and if it fail only then return Portrait. But you can return instead whatever you want, I just used it as example – ManWithBear Mar 28 '19 at 17:02
  • Ok, thanks a lot. Haven’t tried yet but will give it a try tonight and let you know – jeddi Mar 29 '19 at 15:40
  • I have updated the question with more details as I don't manage to adapt your code to mine. Thank you – jeddi Mar 30 '19 at 11:31
  • It doesn't seem to work. It does initialize each view in the desired orientation, but then it fails in preventing autorotation despite the flag being set to FALSE. – jeddi Apr 01 '19 at 12:16
0

I've read that recently it is no longer possible to apply individual settings to each view, which seems to be absurd.

It isn’t absurd, and it is the case. You cannot make different children of a tab view controller adopt different forced orientations.

The only way to force an orientation different from the current orientation is through a presented view controller.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Can you please expand on how to do that? I definitely need certain views only in portrait mode and others in landscape mode, without being able to autorotate. Would it work if I separated them in this way: all portrait views inside the tabcontroller; the single landscape view outside the tabcontroller, being triggered by pressing on one of the tabs of the tabcontroller, leaving the same. Then to go back to it, the tabbcarcontroller would need to be reinitialized again. Would that prevent the autorotation or not? – jeddi Apr 01 '19 at 12:22
  • I don’t know what more I can say. A presented view controller is a presented view controller. I’ve been giving this same answer for years. See https://stackoverflow.com/a/15301322/341994. – matt Apr 01 '19 at 12:41