I´m having this issue with iOS 6 SDK: I´m having some views that should be allowed to rotate (e.g. a videoview), and some that don´t. Now I understand I have to check all orientations in the app´s Info.plist and then sort out in each ViewController, what should happen. But it doesn´t work! The app always rotates to the orientations, that are given in the Info.plist.
Info.plist:
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
any ViewController that shouldn´t be allowed to rotate:
//deprecated
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
Observation: App rotates to landscape and portrait orientation. Any ideas why or what I´m doing wrong?
Cheers, Marc
Edit: My latest findings also indicate, that if you want to have rotation at some point in your app, you have to activate all four rotation directions in your project settings or Info.plist. An alternative to this is to override
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
in your AppDelegate, which overrides the Info.plist. It isn´t possible anymore to set only Portrait in your Info.plist and then having rotation in some ViewController by overriding shouldAutorotateToInterfaceOrientation or supportedInterfaceOrientations.
If your ViewController is a child of a UINavigationController or UITabBarController, then it is the parent that is your problem. You might need to subclass that parent view controller, just overriding those InterfaceOrientation methods as you've shown in your question
EDIT:
Example for portrait only TabBarController
@interface MyTabBarController : UITabBarController
{
}
@end
@implementation MyTabBarController
// put your shouldAutorotateToInterfaceOrientation and other overrides here
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
@end
Adding to CSmith's answer above, the following code in a UINavigationController subclass allows delegation to the top view controller in the way that I expected this to work in the first place:
- (BOOL)shouldAutorotate;
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
if ([[self topViewController] respondsToSelector:@selector(supportedInterfaceOrientations)])
return [[self topViewController] supportedInterfaceOrientations];
else
return [super supportedInterfaceOrientations];
}
Here's another alternative to CSmith's approach.
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;
}
Try to add this category:
@interface UINavigationController(InterfaceOrientation)
@end
@implementation UINavigationController(InterfaceOrientation)
- (NSUInteger) supportedInterfaceOrientations {
if (self.viewControllers.count > 0)
return [[self.viewControllers objectAtIndex:0] supportedInterfaceOrientations];
else
return UIInterfaceOrientationMaskAll;
}
@end
For people using UINavigationController and Swift, you can add this extension to your project. After that, navigation controllers delegate the control to their child controller.
extension UINavigationController {
override public func supportedInterfaceOrientations()
-> UIInterfaceOrientationMask {
if let ctrl = topViewController {
return ctrl.supportedInterfaceOrientations()
}
return super.supportedInterfaceOrientations()
}
override public func shouldAutorotate() -> Bool {
if let ctrl = topViewController {
return ctrl.shouldAutorotate()
}
return super.shouldAutorotate()
}
}
Further addition to @CSmith and @EvanSchoenberg.
If you have some views that rotate, and some views that don't, you must create a custom instance of the UITabBarController
, yet still let each UIViewController
decide.
- (BOOL)shouldAutorotate;
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
UIViewController * top;
UIViewController * tab = self.selectedViewController;
if([tab isKindOfClass:
([UINavigationController class])]) {
top = [((UINavigationController *)tab)
topViewController];
}
if ([top respondsToSelector:@selector(supportedInterfaceOrientations)])
return [top supportedInterfaceOrientations];
else
return [super supportedInterfaceOrientations];
}
@Alvivi's answer updated for Swift 4.
extension UINavigationController {
// Look for the supportedInterfaceOrientations of the topViewController
// Otherwise, viewController will rotate irrespective of the value returned by the ViewController
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if let ctrl = self.topViewController {
return ctrl.supportedInterfaceOrientations
}
return super.supportedInterfaceOrientations
}
// Look for the shouldAutorotate of the topViewController
// Otherwise, viewController will rotate irrespective of the value returned by the ViewController
override open var shouldAutorotate: Bool {
if let ctrl = self.topViewController {
return ctrl.shouldAutorotate
}
return super.shouldAutorotate
}
}
@Shimanski Artem's answer is good, but I think using the topmost (currently visible) controller is better solution:
@interface UINavigationController(InterfaceOrientation)
@end
@implementation UINavigationController(InterfaceOrientation)
- (NSUInteger) supportedInterfaceOrientations {
if (self.viewControllers.count > 0){
return [[self.viewControllers objectAtIndex:[self.viewControllers count] - 1] supportedInterfaceOrientations];
}
return UIInterfaceOrientationMaskAll;
}
@end
As an alternate option, in case you want to preserve pre-iOS6 rotation functionality in your app:
Here's a helpful bit of code on github that swizzles the method calls for iOS6 so that rotation works like it did on iOS4/iOS4. This really helped me, as I'm supporting a legacy app that really micro-manages its rotations. It would have been a lot of work to implement the changes required for iOS6. Kudos to the user who posted it.
来源:https://stackoverflow.com/questions/12410031/ios-6-rotations-supportedinterfaceorientations-doesn%c2%b4t-work