Question

I have a Monotouch 6.0.10 iPhone app using the 6.1 SDK, but targeted to iOS 4.0 and up, where I am trying unsuccessfully to force just one of the views to portrait orientation, using ShouldAutorotateToInterfaceOrientation. It's now deprecated I realize, but nevertheless necessary to support iOS4/iOS5 devices.

To try to isolate the problem I wrote a minimal test app. It is XIB-less and has a UITabBarController with one tab. The tab has a UINavigationController and the UINavigationController has a UIViewController (with a hello world button to click).

In AppDelegate I have:

tabController = new TabController();
window.RootViewController = tabController;

In the UITabBarController and in the UINavigationController I have:

public override bool ShouldAutorotateToInterfaceOrientation(UIInterfaceOrientation toInterfaceOrientation)
    {
        return true;
    }

In the UIViewController I have:

public override bool ShouldAutorotateToInterfaceOrientation(UIInterfaceOrientation toInterfaceOrientation)
{
    if ( toInterfaceOrientation == UIInterfaceOrientation.Portrait )
    {
        return true;
    }
    else
    {
        return false;
    }
}

Well, on an iOS 6.1 device at least, those ShouldAutorotateToInterfaceOrientation's seem to be completely ignored. Breakpoints there don't get reached, and if I force them to return false in every case, rotations still happen.

My understanding is that ShouldAutomaticallyForwardRotationMethods defaults to true so that would not seem to offer a solution. Have combed the forums with no luck, except a suggestion from Glen Schmidt here: iOS 6 rotations: supportedInterfaceOrientations doesn´t work? but unfortunately I'm lost on how to translate that to MonoTouch:

QUOTE

If you want to replicate the pre-iOS 6 behaviour where all the views in the navigation stack / tab bar have to agree on an allowable set of orientations, put this in your subclass of UITabBarController or UINavigationController:

- (NSUInteger)supportedInterfaceOrientations
{
    NSUInteger orientations = [super supportedInterfaceOrientations];

    for (UIViewController *controller in self.viewControllers)
        orientations = orientations & [controller supportedInterfaceOrientations];

    return orientations;
}

UNQUOTE

I understand also that I can't even hope to solve it just for my iOS6 users via ShouldAutoRotate/SupportedInterfaceOrientations because this would cause iOS4/IOS5 rotations to fail.

Any suggestion much appreciated!

Bill.

Was it helpful?

Solution

Found a solution that works, after quite a bit of thrashing about. Somebody might be able to improve on this.

PROBLEM

My app, based on SDK 6.1, targets iOS4, iOS5 and iOS6 devices. It needs to allow all screens to rotate, except for one which must be fixed in portrait orientation. The app has a UITabBarController, most tabs have a UINavigationController with stacked views beneath.

SOLUTION

For iOS4/iOS5 users, the key is the deprecated ShouldAutorotateToInterfaceOrientation() method in the app's root view controller (tab bar controller in my case). This method is not called automatically in any other view controller, but of course the root view controller can invoke a method of the same name in the current view controller.

For iOS6 users, the key is ShouldAutorotate() / GetSupportedInterfaceOrientations() in the app's root view controller. Again, these methods are not called automatically in any other view controller but the root view controller can invoke methods of the same name in the current view controller.

For my simple test app described in the original post:

In AppDelegate/FinishedLaunching:

window.RootViewController = tabController;

In AppDelegate:

public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations (UIApplication application, UIWindow forWindow)
{
    return UIInterfaceOrientationMask.All;
}

In TabController:

public override bool ShouldAutorotateToInterfaceOrientation(UIInterfaceOrientation toInterfaceOrientation)  // iOS4/iOS5 only
{
    try
    {
        UINavigationController navController = (UINavigationController)SelectedViewController;
        UIViewController targetController = navController.ViewControllers[0];
        if ( targetController.Title == "Greetings")
        {
            if ( toInterfaceOrientation == UIInterfaceOrientation.Portrait )
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
    catch
    {
        return true;
    }
    return true;
}

public override bool ShouldAutorotate() // iOS6+ only
{
    return true;
}

public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations()  // iOS6+ only
{
    try
    {
        UINavigationController navController = (UINavigationController)SelectedViewController;
        UIViewController targetController = navController.ViewControllers[0];
        return targetController.GetSupportedInterfaceOrientations();
    }
    catch
    {
        return UIInterfaceOrientationMask.All;
    }
    return UIInterfaceOrientationMask.All;
}

In the view controller that needs to be portrait:

public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations()  // iOS6+ only
{
    return UIInterfaceOrientationMask.Portrait;
}

My actual app needs something slightly more elaborate but along the same lines. For example in the tabbarcontroller:

public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations()
{
    try
    {
        UINavigationController navController = (UINavigationController)SelectedViewController;
        if ( navController.Title == "Tracking" )        // Are we on the Tracking tab?
        {
            // Yes. Looking for RedLaser's BarcodePickerController
            UIViewController targetController = navController.ViewControllers[1];       // BarcodePicker would be second on nav stack
            string controllerType = targetController.GetType().Name;

            if ( controllerType == "BarcodePickerController" )                          // Is this BarcodePicker?   
            {
                return UIInterfaceOrientationMask.Portrait;                             // Yes, force portrait orientation                          
            }
        }
        else
        {
            return UIInterfaceOrientationMask.All;                                      // No, allow any orientation
        }
    }
    catch
    {
        return UIInterfaceOrientationMask.All;                                          // Not BarcodePicker, allow any orientation
    }
    return UIInterfaceOrientationMask.All;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top