0

I am trying to get device rotation right.

  • I am testing on iPad 8.x/9.x simulator
  • I have 4 VCs
    • VC1 - Both Portrait and Landscape
    • VC2 - Both Portrait and Landscape
    • VC3 - Only Portrait
    • VC4 - Both Portrait and Landscape

Goal: to have VC3 display PortraitView at all times (same as if app orientation was fixed to portrait).

I tried

@implementation RotationAwareNavigationController

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    UIViewController *top = self.topViewController;
    return top.supportedInterfaceOrientations;
}

-(BOOL)shouldAutorotate {
    UIViewController *top = self.topViewController;
    return [top shouldAutorotate];
}

@end

In VC which is portrait

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

But it does not work meaning view not displayed in Portrait dimensions Am I missing something?

I am sure it can be done as when I use ImagePickerController provided my iOS, it is fixed to Portrait. I just dont know how to do it.

GJain
  • 5,025
  • 6
  • 48
  • 82
  • I don't understand how you can support only portrait AND handle device rotation at the same time? Support ONLY portrait means there is no rotation. Can you explain in more detail what wanting both of those things means? – keithbhunter Jul 12 '16 at 17:31
  • So I want to have VC in Portrait view. But when device is rotated, I want to present another view controller on top of it which is landscape. I did it by listenting to OrientationChangeNotifications. But I wanted to use viewWillTransitionToSize if possible. Otherwise I will go back to listenting to OrientationChangeNotifications. – GJain Jul 12 '16 at 17:33
  • Ok I made edit to my question. As long as I can fix it to Portrait, it will work for me. – GJain Jul 12 '16 at 17:36
  • 1
    @user2384694 check this question http://stackoverflow.com/questions/38308919/unable-to-force-uiviewcontroller-orientation/38308987#38308987 – Reinier Melian Jul 12 '16 at 18:22

1 Answers1

0

To support differing orientations in different view controllers, you will need to do a few things. First, you need to check all the checkboxes for orientations you want to support in your target's General settings tab.

Second, anytime you call presentViewController or dismissViewController in your app, the UIApplicationDelegate method application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask will be called. You can use this method to restrict (or allow) specific orientations each time a new view controller is presented or dismissed. Unfortunately, it isn't as simple as just returning a UIInterfaceOrientationMask here. You will need to find the view controller that is going to be showing on screen and return the orientations that it supports. Here is an example of this:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    guard let window = window, let rootViewController = window.rootViewController else {
        return UIDevice.currentDevice().userInterfaceIdiom == .Pad ? .All : .AllButUpsideDown  // iOS defaults
    }

    // Let the view controller being shown decide what orientation it wants to support. This method will be called anytime a new view controller is presented on screen.
    return findVisibleViewController(rootViewController: rootViewController).supportedInterfaceOrientations()
}

/// Searches the view hierarchy recursively and finds the view controller that is currently showing.
private func findVisibleViewController(rootViewController rootViewController: UIViewController) -> UIViewController {
    if let presentedViewController = rootViewController.presentedViewController {
        // Search for a modal view first.
        return self.findVisibleViewController(rootViewController: presentedViewController)
    } else if
        let navigationController = rootViewController as? UINavigationController,
        let visibleViewController = navigationController.visibleViewController {
        // Then search navigation controller's views to find its visible controller.
        return self.findVisibleViewController(rootViewController: visibleViewController)
    } else if let splitViewController = rootViewController as? UISplitViewController {
        // Then try the split view controller. This will be the true root view controller. Use the master here since the detail just shows web views.
        return self.findVisibleViewController(rootViewController: splitViewController.viewControllers[0])
    } else {
        // Guess we found the visible view controller, because none of the other conditions were met.
        return rootViewController
    }
}

findVisibleViewController(_:) is an example from one of my projects and is tailored to the exact view controller hierarchy in my app. You will need to edit this for your own app in a way that makes sense for your hierarchy.

Third, you will need to implement supportedInterfaceOrientations() for most, if not all, of your view controllers.

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return // portrait, landscape, or combinations of those.
}

Finally, this only handles situations where you presented or dismissed something modally. For show (push) segues, the orientation of the navigation controller will be used for every new view controller pushed onto the stack. If you need more fine grained control here, you will need to force the orientation to happen. Here is an example of that:

// Some other view had the screen in landscape, so force the view to return to portrait
UIDevice.currentDevice().setValue(UIInterfaceOrientation.Portrait.rawValue, forKey: "orientation")
keithbhunter
  • 12,258
  • 4
  • 33
  • 58