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;
}